Add Legal Office seal and complete Azure CDN deployment

- Add Legal Office of the Master seal (SVG design with Maltese Cross, scales of justice, legal scroll)
- Create legal-office-manifest-template.json for Legal Office credentials
- Update SEAL_MAPPING.md and DESIGN_GUIDE.md with Legal Office seal documentation
- Complete Azure CDN infrastructure deployment:
  - Resource group, storage account, and container created
  - 17 PNG seal files uploaded to Azure Blob Storage
  - All manifest templates updated with Azure URLs
  - Configuration files generated (azure-cdn-config.env)
- Add comprehensive Azure CDN setup scripts and documentation
- Fix manifest URL generation to prevent double slashes
- Verify all seals accessible via HTTPS
This commit is contained in:
defiQUG
2025-11-12 22:03:42 -08:00
parent 8649ad4124
commit 92cc41d26d
258 changed files with 16021 additions and 1260 deletions

View File

@@ -13,11 +13,11 @@ export class ApiClient {
constructor(baseURL?: string) {
// Initialize service clients - each manages its own axios instance
this.identity = new IdentityClient();
this.eresidency = new EResidencyClient();
this.intake = new IntakeClient();
this.finance = new FinanceClient();
this.dataroom = new DataroomClient();
this.identity = new IdentityClient(baseURL);
this.eresidency = new EResidencyClient(baseURL);
this.intake = new IntakeClient(baseURL);
this.finance = new FinanceClient(baseURL);
this.dataroom = new DataroomClient(baseURL);
}
setAuthToken(token: string): void {

View File

@@ -1,4 +1,4 @@
import { ApiClient } from './client';
import axios, { AxiosInstance } from 'axios';
import type { eResidencyApplication, ApplicationStatus } from '@the-order/schemas';
export interface SubmitApplicationRequest {
@@ -36,14 +36,60 @@ export interface AdjudicateRequest {
}
export class EResidencyClient {
constructor(private client: ApiClient) {}
protected client: AxiosInstance;
async submitApplication(request: SubmitApplicationRequest) {
return this.client.post<eResidencyApplication>('/applications', request);
constructor(baseURL?: string) {
const apiBaseURL =
baseURL ||
(typeof window !== 'undefined'
? process.env.NEXT_PUBLIC_ERESIDENCY_SERVICE_URL || 'http://localhost:4001'
: 'http://localhost:4001');
this.client = axios.create({
baseURL: apiBaseURL,
headers: {
'Content-Type': 'application/json',
},
});
// Set up request interceptor for authentication
this.client.interceptors.request.use(
(config) => {
const token = this.getAuthToken();
if (token) {
config.headers.Authorization = `Bearer ${token}`;
}
return config;
},
(error) => Promise.reject(error)
);
}
async getApplication(id: string) {
return this.client.get<eResidencyApplication>(`/applications/${id}`);
private getAuthToken(): string | null {
if (typeof window === 'undefined') return null;
return localStorage.getItem('auth_token');
}
setAuthToken(token: string): void {
if (typeof window !== 'undefined') {
localStorage.setItem('auth_token', token);
}
}
clearAuthToken(): void {
if (typeof window !== 'undefined') {
localStorage.removeItem('auth_token');
}
}
async submitApplication(request: SubmitApplicationRequest): Promise<eResidencyApplication> {
const response = await this.client.post<eResidencyApplication>('/applications', request);
return response.data;
}
async getApplication(id: string): Promise<eResidencyApplication> {
const response = await this.client.get<eResidencyApplication>(`/applications/${id}`);
return response.data;
}
async getReviewQueue(filters?: {
@@ -52,38 +98,50 @@ export class EResidencyClient {
assignedTo?: string;
limit?: number;
offset?: number;
}) {
}): Promise<{
applications: eResidencyApplication[];
total: number;
}> {
const params = new URLSearchParams();
if (filters?.riskBand) params.append('riskBand', filters.riskBand);
if (filters?.status) params.append('status', filters.status);
if (filters?.assignedTo) params.append('assignedTo', filters.assignedTo);
if (filters?.limit) params.append('limit', filters.limit.toString());
if (filters?.offset) params.append('offset', filters.offset.toString());
return this.client.get<{
const response = await this.client.get<{
applications: eResidencyApplication[];
total: number;
}>(`/review/queue?${params.toString()}`);
return response.data;
}
async getApplicationForReview(id: string) {
return this.client.get<eResidencyApplication>(`/review/applications/${id}`);
async getApplicationForReview(id: string): Promise<eResidencyApplication> {
const response = await this.client.get<eResidencyApplication>(`/review/applications/${id}`);
return response.data;
}
async adjudicateApplication(id: string, request: AdjudicateRequest) {
return this.client.post<eResidencyApplication>(`/review/applications/${id}/adjudicate`, request);
async adjudicateApplication(id: string, request: AdjudicateRequest): Promise<eResidencyApplication> {
const response = await this.client.post<eResidencyApplication>(`/review/applications/${id}/adjudicate`, request);
return response.data;
}
async revokeCredential(residentNumber: string, reason: string) {
return this.client.post('/applications/revoke', { residentNumber, reason });
async revokeCredential(residentNumber: string, reason: string): Promise<void> {
await this.client.post('/applications/revoke', { residentNumber, reason });
}
async getStatus() {
return this.client.get<Array<{
async getStatus(): Promise<Array<{
residentNumber: string;
status: string;
issuedAt?: string;
revokedAt?: string;
}>> {
const response = await this.client.get<Array<{
residentNumber: string;
status: string;
issuedAt?: string;
revokedAt?: string;
}>>('/status');
return response.data;
}
}

View File

@@ -1,4 +1,4 @@
import { ApiClient } from './client';
import axios, { AxiosInstance } from 'axios';
import type { eResidentCredential, eCitizenCredential } from '@the-order/schemas';
export interface IssueVCRequest {
@@ -49,18 +49,73 @@ export interface CredentialMetrics {
}
export class IdentityClient {
constructor(private client: ApiClient) {}
protected client: AxiosInstance;
async issueCredential(request: IssueVCRequest) {
return this.client.post<{ credential: eResidentCredential | eCitizenCredential }>('/vc/issue', request);
constructor(baseURL?: string) {
const apiBaseURL =
baseURL ||
(typeof window !== 'undefined'
? process.env.NEXT_PUBLIC_IDENTITY_SERVICE_URL || 'http://localhost:4002'
: 'http://localhost:4002');
this.client = axios.create({
baseURL: apiBaseURL,
headers: {
'Content-Type': 'application/json',
},
});
// Set up request interceptor for authentication
this.client.interceptors.request.use(
(config) => {
const token = this.getAuthToken();
if (token) {
config.headers.Authorization = `Bearer ${token}`;
}
return config;
},
(error) => Promise.reject(error)
);
}
async verifyCredential(request: VerifyVCRequest) {
return this.client.post<{ valid: boolean }>('/vc/verify', request);
private getAuthToken(): string | null {
if (typeof window === 'undefined') return null;
return localStorage.getItem('auth_token');
}
async batchIssue(request: BatchIssuanceRequest) {
return this.client.post<{
setAuthToken(token: string): void {
if (typeof window !== 'undefined') {
localStorage.setItem('auth_token', token);
}
}
clearAuthToken(): void {
if (typeof window !== 'undefined') {
localStorage.removeItem('auth_token');
}
}
async issueCredential(request: IssueVCRequest): Promise<{ credential: eResidentCredential | eCitizenCredential }> {
const response = await this.client.post<{ credential: eResidentCredential | eCitizenCredential }>('/vc/issue', request);
return response.data;
}
async verifyCredential(request: VerifyVCRequest): Promise<{ valid: boolean }> {
const response = await this.client.post<{ valid: boolean }>('/vc/verify', request);
return response.data;
}
async batchIssue(request: BatchIssuanceRequest): Promise<{
jobId: string;
total: number;
accepted: number;
results: Array<{
index: number;
credentialId?: string;
error?: string;
}>;
}> {
const response = await this.client.post<{
jobId: string;
total: number;
accepted: number;
@@ -70,21 +125,31 @@ export class IdentityClient {
error?: string;
}>;
}>('/vc/issue/batch', request);
return response.data;
}
async revokeCredential(credentialId: string, reason?: string) {
return this.client.post('/vc/revoke', { credentialId, reason });
async revokeCredential(credentialId: string, reason?: string): Promise<void> {
await this.client.post('/vc/revoke', { credentialId, reason });
}
async getMetrics(startDate?: Date, endDate?: Date) {
async getMetrics(startDate?: Date, endDate?: Date): Promise<CredentialMetrics> {
const params = new URLSearchParams();
if (startDate) params.append('startDate', startDate.toISOString());
if (endDate) params.append('endDate', endDate.toISOString());
return this.client.get<CredentialMetrics>(`/metrics?${params.toString()}`);
const response = await this.client.get<CredentialMetrics>(`/metrics?${params.toString()}`);
return response.data;
}
async getMetricsDashboard() {
return this.client.get<{
async getMetricsDashboard(): Promise<{
summary: CredentialMetrics;
trends: {
daily: Array<{ date: string; count: number }>;
weekly: Array<{ week: string; count: number }>;
monthly: Array<{ month: string; count: number }>;
};
topCredentialTypes: Array<{ type: string; count: number; percentage: number }>;
}> {
const response = await this.client.get<{
summary: CredentialMetrics;
trends: {
daily: Array<{ date: string; count: number }>;
@@ -93,6 +158,7 @@ export class IdentityClient {
};
topCredentialTypes: Array<{ type: string; count: number; percentage: number }>;
}>('/metrics/dashboard');
return response.data;
}
async searchAuditLogs(filters: {
@@ -107,8 +173,35 @@ export class IdentityClient {
ipAddress?: string;
page?: number;
pageSize?: number;
}) {
return this.client.post('/metrics/audit/search', filters);
}): Promise<{
logs: Array<{
id: string;
action: string;
credentialId?: string;
subjectDid?: string;
performedBy?: string;
timestamp: string;
metadata?: Record<string, unknown>;
}>;
total: number;
page: number;
pageSize: number;
}> {
const response = await this.client.post<{
logs: Array<{
id: string;
action: string;
credentialId?: string;
subjectDid?: string;
performedBy?: string;
timestamp: string;
metadata?: Record<string, unknown>;
}>;
total: number;
page: number;
pageSize: number;
}>('/metrics/audit/search', filters);
return response.data;
}
}

View File

@@ -1,7 +1,7 @@
import axios, { AxiosInstance } from 'axios';
export interface DocumentUpload {
file: File | Blob;
file: File | Blob | Buffer;
documentType: string;
metadata?: Record<string, unknown>;
}
@@ -65,7 +65,11 @@ export class IntakeClient {
async uploadDocument(upload: DocumentUpload): Promise<DocumentMetadata> {
const formData = new FormData();
formData.append('file', upload.file);
// FormData.append accepts File, Blob, or string, but Buffer needs to be converted
const file: File | Blob = upload.file instanceof Buffer
? new Blob([new Uint8Array(upload.file)])
: (upload.file as File | Blob);
formData.append('file', file);
formData.append('documentType', upload.documentType);
if (upload.metadata) {
formData.append('metadata', JSON.stringify(upload.metadata));

View File

@@ -2,11 +2,14 @@
"extends": "../../tsconfig.base.json",
"compilerOptions": {
"outDir": "./dist",
"rootDir": "./src",
"composite": true,
"declaration": true,
"declarationMap": true
"declarationMap": true,
"lib": ["dom", "dom.iterable", "esnext"]
},
"references": [
{ "path": "../schemas" }
],
"include": ["src/**/*"],
"exclude": ["node_modules", "dist"]
}

View File

@@ -20,7 +20,8 @@
"jsonwebtoken": "^9.0.2",
"multibase": "^4.0.1",
"node-fetch": "^2.7.0",
"node-forge": "^1.3.1"
"node-forge": "^1.3.1",
"sharp": "^0.34.5"
},
"devDependencies": {
"@types/jsonwebtoken": "^9.0.5",

View File

@@ -55,20 +55,22 @@ export class DIDResolver {
return (await response.json()) as DIDDocument;
} else if (method === 'key') {
// did:key resolution - generate document from key
const publicKeyMultibase = identifier;
return {
const publicKeyMultibase: string = identifier;
const verificationMethodObj: VerificationMethod = {
id: `${did}#keys-1`,
type: 'Ed25519VerificationKey2020',
controller: did,
publicKeyMultibase: publicKeyMultibase,
};
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
const verificationMethodArray: VerificationMethod[] = [verificationMethodObj];
const result: DIDDocument = {
id: did,
'@context': ['https://www.w3.org/ns/did/v1'],
verificationMethod: [
{
id: `${did}#keys-1`,
type: 'Ed25519VerificationKey2020',
controller: did,
publicKeyMultibase,
},
],
verificationMethod: verificationMethodArray,
authentication: [`${did}#keys-1`],
};
return result;
}
throw new Error(`Unsupported DID method: ${method}`);
@@ -160,7 +162,8 @@ export class DIDResolver {
}
// Verify signature using @noble/ed25519
return await ed25519Verify(signatureBytes, messageBytes, publicKey);
// ed25519Verify is synchronous, but we keep async for consistency
return Promise.resolve(ed25519Verify(signatureBytes, messageBytes, publicKey));
} catch (error) {
console.error('Ed25519 verification failed:', error);
return false;
@@ -207,11 +210,11 @@ export class DIDResolver {
/**
* Verify signature with RSA public key
*/
private async verifyRSA(
private verifyRSA(
jwk: { n?: string; e?: string },
message: string,
signature: string
): Promise<boolean> {
): boolean {
try {
if (!jwk.n || !jwk.e) {
return false;
@@ -271,7 +274,7 @@ export class DIDResolver {
// RSA keys
if (jwk.kty === 'RSA') {
return await this.verifyRSA(jwk, message, signature);
return this.verifyRSA(jwk, message, signature);
}
// Ed25519 in JWK format (less common)

View File

@@ -84,7 +84,6 @@ export class EIDASToEntraBridge {
}> {
// Step 0: Validate and encode document if needed
let documentBase64: string;
const errors: string[] = [];
if (document instanceof Buffer) {
// Encode buffer to base64
@@ -92,7 +91,7 @@ export class EIDASToEntraBridge {
} else {
// Validate base64 string
const validation = validateBase64File(
document,
document as string,
validationOptions || {
maxSize: FILE_SIZE_LIMITS.MEDIUM,
allowedMimeTypes: [
@@ -112,7 +111,7 @@ export class EIDASToEntraBridge {
};
}
documentBase64 = document;
documentBase64 = document as string;
}
// Step 1: Request eIDAS signature
@@ -140,8 +139,9 @@ export class EIDASToEntraBridge {
// Step 3: Trigger Logic App workflow if configured
if (this.logicAppsClient) {
try {
const documentId = document instanceof Buffer ? document.toString('base64').substring(0, 100) : (document as string).substring(0, 100);
await this.logicAppsClient.triggerEIDASVerification(
document,
documentId,
userId,
this.eidasProvider['config'].providerUrl
);

View File

@@ -252,10 +252,10 @@ export class EIDASProvider {
/**
* Validate certificate without signature verification
*/
async validateCertificate(
validateCertificate(
certificate: string,
chain?: string[]
): Promise<CertificateValidationResult> {
): CertificateValidationResult {
return this.validateCertificateChain(certificate, chain);
}
}

View File

@@ -0,0 +1,183 @@
/**
* Credential Image/Logo Management for Entra VerifiedID
* Handles image conversion and validation for credential display
*/
export interface CredentialImageConfig {
logoUri?: string;
backgroundColor?: string;
textColor?: string;
description?: string;
}
export interface ImageFormat {
format: 'svg' | 'png' | 'jpg' | 'jpeg' | 'bmp';
data: string | Buffer;
mimeType: string;
}
/**
* Supported image formats for Entra VerifiedID
* Note: Entra VerifiedID officially supports PNG, JPG, BMP
* SVG may work but PNG is recommended for compatibility
*/
export const SUPPORTED_FORMATS = ['png', 'jpg', 'jpeg', 'bmp', 'svg'] as const;
export type SupportedFormat = typeof SUPPORTED_FORMATS[number];
/**
* Validate image format
*/
export function validateImageFormat(format: string): format is SupportedFormat {
return SUPPORTED_FORMATS.includes(format.toLowerCase() as SupportedFormat);
}
/**
* Get MIME type for image format
*/
export function getImageMimeType(format: SupportedFormat): string {
const mimeTypes: Record<SupportedFormat, string> = {
svg: 'image/svg+xml',
png: 'image/png',
jpg: 'image/jpeg',
jpeg: 'image/jpeg',
bmp: 'image/bmp',
};
return mimeTypes[format] || 'image/png';
}
/**
* Convert SVG to PNG (if needed for Entra compatibility)
* Note: This requires additional dependencies like sharp or svg2png
*/
export async function convertSvgToPng(
svgData: string | Buffer,
width: number = 200,
height: number = 200
): Promise<Buffer> {
// Check if sharp is available (optional dependency)
try {
// eslint-disable-next-line @typescript-eslint/no-require-imports
const sharp = require('sharp');
const svgBuffer = typeof svgData === 'string' ? Buffer.from(svgData) : svgData;
return await sharp(svgBuffer)
.resize(width, height)
.png()
.toBuffer();
} catch (error) {
// If sharp is not available, return original SVG
// Note: Entra may accept SVG, but PNG is recommended
console.warn('sharp not available, using SVG directly (may not be supported by Entra)');
return typeof svgData === 'string' ? Buffer.from(svgData) : svgData;
}
}
/**
* Prepare image for Entra VerifiedID
* Converts SVG to PNG if needed, validates format
*/
export async function prepareCredentialImage(
imageData: string | Buffer,
format?: SupportedFormat
): Promise<{
data: Buffer;
mimeType: string;
format: SupportedFormat;
}> {
let imageBuffer: Buffer;
let detectedFormat: SupportedFormat;
let mimeType: string;
// Detect format if not provided
if (!format) {
if (typeof imageData === 'string') {
// Check if it's a data URL
if (imageData.startsWith('data:')) {
const match = imageData.match(/data:image\/([^;]+)/);
detectedFormat = (match?.[1]?.toLowerCase() || 'png') as SupportedFormat;
} else if (imageData.trim().startsWith('<svg')) {
detectedFormat = 'svg';
} else {
detectedFormat = 'png'; // Default
}
} else {
// Try to detect from buffer (basic check)
const header = imageData.toString('hex', 0, 4);
if (header.startsWith('89504e47')) {
detectedFormat = 'png';
} else if (header.startsWith('ffd8ff')) {
detectedFormat = 'jpg';
} else if (header.startsWith('424d')) {
detectedFormat = 'bmp';
} else {
detectedFormat = 'png'; // Default
}
}
} else {
detectedFormat = format;
}
// Convert to buffer if string
if (typeof imageData === 'string') {
if (imageData.startsWith('data:')) {
// Extract base64 data
const base64Data = imageData.split(',')[1];
imageBuffer = Buffer.from(base64Data, 'base64');
} else {
imageBuffer = Buffer.from(imageData);
}
} else {
imageBuffer = imageData;
}
// Convert SVG to PNG for Entra compatibility
if (detectedFormat === 'svg') {
try {
imageBuffer = await convertSvgToPng(imageBuffer);
detectedFormat = 'png';
mimeType = 'image/png';
} catch (error) {
console.warn('SVG to PNG conversion failed, using SVG (may not be supported)', error);
mimeType = 'image/svg+xml';
}
} else {
mimeType = getImageMimeType(detectedFormat);
}
// Validate format
if (!validateImageFormat(detectedFormat)) {
throw new Error(`Unsupported image format: ${detectedFormat}. Supported: ${SUPPORTED_FORMATS.join(', ')}`);
}
return {
data: imageBuffer,
mimeType,
format: detectedFormat,
};
}
/**
* Create data URL from image
*/
export function createImageDataUrl(imageData: Buffer, mimeType: string): string {
const base64 = imageData.toString('base64');
return `data:${mimeType};base64,${base64}`;
}
/**
* Get recommended image specifications for Entra VerifiedID
*/
export function getRecommendedImageSpecs(): {
format: 'png' | 'jpg';
width: number;
height: number;
maxSizeKB: number;
} {
return {
format: 'png', // Recommended format
width: 200,
height: 200,
maxSizeKB: 100, // Max 100KB recommended
};
}

View File

@@ -0,0 +1,180 @@
/**
* Enhanced Microsoft Entra VerifiedID connector
* Adds retry logic, multi-manifest support, and improved error handling
*/
import { EntraVerifiedIDClient, EntraVerifiedIDConfig, VerifiableCredentialRequest, VerifiableCredentialResponse, VerifiableCredentialStatus, VerifiedCredential } from './entra-verifiedid';
export interface RetryConfig {
maxRetries?: number;
initialDelayMs?: number;
maxDelayMs?: number;
backoffMultiplier?: number;
retryableStatusCodes?: number[];
}
export interface MultiManifestConfig extends EntraVerifiedIDConfig {
manifests?: Record<string, string>; // manifest name -> manifest ID mapping
}
const DEFAULT_RETRY_CONFIG: Required<RetryConfig> = {
maxRetries: 3,
initialDelayMs: 1000,
maxDelayMs: 10000,
backoffMultiplier: 2,
retryableStatusCodes: [429, 500, 502, 503, 504],
};
/**
* Sleep utility for retry delays
*/
function sleep(ms: number): Promise<void> {
return new Promise((resolve) => setTimeout(resolve, ms));
}
/**
* Check if an error is retryable
*/
function isRetryableError(statusCode: number, retryableStatusCodes: number[]): boolean {
return retryableStatusCodes.includes(statusCode);
}
/**
* Enhanced Entra VerifiedID client with retry logic and multi-manifest support
*/
export class EnhancedEntraVerifiedIDClient extends EntraVerifiedIDClient {
private retryConfig: Required<RetryConfig>;
private manifests: Record<string, string>;
constructor(config: MultiManifestConfig, retryConfig?: RetryConfig) {
super(config);
this.retryConfig = { ...DEFAULT_RETRY_CONFIG, ...retryConfig };
this.manifests = config.manifests || {};
// Add default manifest if provided
if (config.credentialManifestId) {
this.manifests['default'] = config.credentialManifestId;
}
}
/**
* Get manifest ID by name, fallback to default
*/
private getManifestId(manifestName?: string): string {
if (manifestName && this.manifests[manifestName]) {
return this.manifests[manifestName];
}
if (this.manifests['default']) {
return this.manifests['default'];
}
throw new Error('No credential manifest ID configured');
}
/**
* Execute a request with retry logic
*/
private async executeWithRetry<T>(
operation: () => Promise<T>,
operationName: string
): Promise<T> {
let lastError: Error | null = null;
let delay = this.retryConfig.initialDelayMs;
for (let attempt = 0; attempt <= this.retryConfig.maxRetries; attempt++) {
try {
return await operation();
} catch (error) {
lastError = error instanceof Error ? error : new Error(String(error));
// Check if error is retryable
const statusCode = (error as any)?.statusCode || (error as any)?.response?.status;
const isRetryable = statusCode && isRetryableError(statusCode, this.retryConfig.retryableStatusCodes);
// Don't retry on last attempt or if error is not retryable
if (attempt === this.retryConfig.maxRetries || !isRetryable) {
throw lastError;
}
// Wait before retrying
await sleep(Math.min(delay, this.retryConfig.maxDelayMs));
delay *= this.retryConfig.backoffMultiplier;
}
}
throw lastError || new Error(`${operationName} failed after ${this.retryConfig.maxRetries} retries`);
}
/**
* Issue credential with retry logic and manifest selection
*/
async issueCredential(
request: VerifiableCredentialRequest & { manifestName?: string }
): Promise<VerifiableCredentialResponse> {
const manifestId = this.getManifestId(request.manifestName);
// Create a modified request without manifestName
const { manifestName, ...credentialRequest } = request;
// Temporarily set manifest ID for this request
const originalManifestId = (this as any).config.credentialManifestId;
(this as any).config.credentialManifestId = manifestId;
try {
return await this.executeWithRetry(
() => super.issueCredential(credentialRequest),
'issueCredential'
);
} finally {
// Restore original manifest ID
(this as any).config.credentialManifestId = originalManifestId;
}
}
/**
* Get issuance status with retry logic
*/
async getIssuanceStatus(requestId: string): Promise<VerifiableCredentialStatus> {
return this.executeWithRetry(
() => super.getIssuanceStatus(requestId),
'getIssuanceStatus'
);
}
/**
* Verify credential with retry logic
*/
async verifyCredential(credential: VerifiedCredential): Promise<boolean> {
return this.executeWithRetry(
() => super.verifyCredential(credential),
'verifyCredential'
);
}
/**
* Create presentation request with retry logic and manifest selection
*/
async createPresentationRequest(
manifestName?: string,
callbackUrl?: string
): Promise<VerifiableCredentialResponse> {
const manifestId = this.getManifestId(manifestName);
return this.executeWithRetry(
() => super.createPresentationRequest(manifestId, callbackUrl),
'createPresentationRequest'
);
}
/**
* Register a new manifest
*/
registerManifest(name: string, manifestId: string): void {
this.manifests[name] = manifestId;
}
/**
* Get all registered manifests
*/
getManifests(): Record<string, string> {
return { ...this.manifests };
}
}

View File

@@ -0,0 +1,96 @@
/**
* Entra VerifiedID Integration Tests
* These tests require actual Entra VerifiedID configuration
* Set ENTRA_TEST_* environment variables to run
*/
import { describe, it, expect, beforeAll } from 'vitest';
import { EnhancedEntraVerifiedIDClient } from './entra-verifiedid-enhanced';
import { getEnv } from '@the-order/shared';
describe('Entra VerifiedID Integration Tests', () => {
let client: EnhancedEntraVerifiedIDClient | null = null;
beforeAll(() => {
const env = getEnv();
if (
!env.ENTRA_TENANT_ID ||
!env.ENTRA_CLIENT_ID ||
!env.ENTRA_CLIENT_SECRET ||
!env.ENTRA_CREDENTIAL_MANIFEST_ID
) {
console.warn('Entra VerifiedID credentials not configured, skipping integration tests');
return;
}
client = new EnhancedEntraVerifiedIDClient({
tenantId: env.ENTRA_TENANT_ID,
clientId: env.ENTRA_CLIENT_ID,
clientSecret: env.ENTRA_CLIENT_SECRET,
credentialManifestId: env.ENTRA_CREDENTIAL_MANIFEST_ID,
});
});
it('should issue a credential', async () => {
if (!client) {
return; // Skip if not configured
}
const request = {
claims: {
email: 'test@example.com',
name: 'Test User',
test: 'true',
},
};
const response = await client.issueCredential(request);
expect(response).toBeDefined();
expect(response.requestId).toBeDefined();
expect(response.url).toBeDefined();
expect(response.expiry).toBeGreaterThan(0);
}, 30000); // 30 second timeout
it('should check issuance status', async () => {
if (!client) {
return; // Skip if not configured
}
// First issue a credential
const issueResponse = await client.issueCredential({
claims: { email: 'test@example.com' },
});
// Then check status
const status = await client.getIssuanceStatus(issueResponse.requestId);
expect(status).toBeDefined();
expect(status.requestId).toBe(issueResponse.requestId);
expect(['request_created', 'request_retrieved', 'issuance_successful', 'issuance_failed']).toContain(status.state);
}, 30000);
it('should support multi-manifest', async () => {
if (!client) {
return; // Skip if not configured
}
// Register additional manifest
client.registerManifest('test', 'test-manifest-id');
const manifests = client.getManifests();
expect(manifests.test).toBe('test-manifest-id');
});
it('should handle retries on transient errors', async () => {
if (!client) {
return; // Skip if not configured
}
// This test would require mocking or simulating transient errors
// For now, we just verify retry config is set
expect(client).toBeDefined();
});
});

View File

@@ -0,0 +1,371 @@
/**
* Entra VerifiedID Client Tests
*/
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
import { EntraVerifiedIDClient, VerifiableCredentialRequest, VerifiedCredential } from './entra-verifiedid';
import { EnhancedEntraVerifiedIDClient } from './entra-verifiedid-enhanced';
import fetch from 'node-fetch';
vi.mock('node-fetch');
describe('EntraVerifiedIDClient', () => {
let client: EntraVerifiedIDClient;
const config = {
tenantId: 'test-tenant-id',
clientId: 'test-client-id',
clientSecret: 'test-client-secret',
credentialManifestId: 'test-manifest-id',
};
beforeEach(() => {
client = new EntraVerifiedIDClient(config);
vi.clearAllMocks();
});
afterEach(() => {
vi.restoreAllMocks();
});
describe('getAccessToken', () => {
it('should cache access token until expiry', async () => {
const mockTokenResponse = {
access_token: 'test-token',
expires_in: 3600,
};
(fetch as any).mockResolvedValueOnce({
ok: true,
json: async () => mockTokenResponse,
});
// First call
const token1 = await (client as any).getAccessToken();
expect(token1).toBe('test-token');
// Second call should use cached token
const token2 = await (client as any).getAccessToken();
expect(token2).toBe('test-token');
expect(fetch).toHaveBeenCalledTimes(1);
});
it('should refresh token when expired', async () => {
const mockTokenResponse = {
access_token: 'test-token',
expires_in: 1, // 1 second expiry
};
(fetch as any).mockResolvedValue({
ok: true,
json: async () => mockTokenResponse,
});
await (client as any).getAccessToken();
// Wait for token to expire
await new Promise((resolve) => setTimeout(resolve, 1100));
// Should fetch new token
await (client as any).getAccessToken();
expect(fetch).toHaveBeenCalledTimes(2);
});
});
describe('validateCredentialRequest', () => {
it('should validate request with valid claims', () => {
const request: VerifiableCredentialRequest = {
claims: { email: 'test@example.com', name: 'Test User' },
};
expect(() => (client as any).validateCredentialRequest(request)).not.toThrow();
});
it('should reject request with empty claims', () => {
const request: VerifiableCredentialRequest = {
claims: {},
};
expect(() => (client as any).validateCredentialRequest(request)).toThrow('At least one claim is required');
});
it('should validate PIN format', () => {
const validRequest: VerifiableCredentialRequest = {
claims: { email: 'test@example.com' },
pin: '1234',
};
expect(() => (client as any).validateCredentialRequest(validRequest)).not.toThrow();
const invalidRequest: VerifiableCredentialRequest = {
claims: { email: 'test@example.com' },
pin: 'abc',
};
expect(() => (client as any).validateCredentialRequest(invalidRequest)).toThrow('PIN must be between 4 and 8 characters');
});
});
describe('issueCredential', () => {
it('should issue credential successfully', async () => {
const mockTokenResponse = {
access_token: 'test-token',
expires_in: 3600,
};
const mockIssuanceResponse = {
requestId: 'test-request-id',
url: 'https://verifiedid.did.msidentity.com/issuance',
expiry: Date.now() + 3600000,
qrCode: 'data:image/png;base64,test',
};
(fetch as any)
.mockResolvedValueOnce({
ok: true,
json: async () => mockTokenResponse,
})
.mockResolvedValueOnce({
ok: true,
json: async () => mockIssuanceResponse,
});
const request: VerifiableCredentialRequest = {
claims: { email: 'test@example.com', name: 'Test User' },
};
const result = await client.issueCredential(request);
expect(result.requestId).toBe('test-request-id');
expect(result.url).toBe('https://verifiedid.did.msidentity.com/issuance');
expect(result.qrCode).toBe('data:image/png;base64,test');
});
it('should throw error when manifest ID is missing', async () => {
const clientWithoutManifest = new EntraVerifiedIDClient({
tenantId: 'test-tenant',
clientId: 'test-client',
clientSecret: 'test-secret',
});
const request: VerifiableCredentialRequest = {
claims: { email: 'test@example.com' },
};
await expect(clientWithoutManifest.issueCredential(request)).rejects.toThrow('Credential manifest ID is required');
});
});
describe('verifyCredential', () => {
it('should verify credential successfully', async () => {
const mockTokenResponse = {
access_token: 'test-token',
expires_in: 3600,
};
const mockVerifyResponse = {
verified: true,
};
(fetch as any)
.mockResolvedValueOnce({
ok: true,
json: async () => mockTokenResponse,
})
.mockResolvedValueOnce({
ok: true,
json: async () => mockVerifyResponse,
});
const credential: VerifiedCredential = {
id: 'test-credential-id',
type: ['VerifiableCredential'],
issuer: 'did:web:test.verifiedid.msidentity.com',
issuanceDate: new Date().toISOString(),
credentialSubject: { email: 'test@example.com' },
proof: {
type: 'JsonWebSignature2020',
created: new Date().toISOString(),
proofPurpose: 'assertionMethod',
verificationMethod: 'did:web:test#key',
jws: 'test-jws',
},
};
const result = await client.verifyCredential(credential);
expect(result).toBe(true);
});
it('should reject invalid credential structure', async () => {
const invalidCredential = {
id: 'test-id',
} as VerifiedCredential;
await expect(client.verifyCredential(invalidCredential)).rejects.toThrow('Credential type is required');
});
});
});
describe('EnhancedEntraVerifiedIDClient', () => {
let client: EnhancedEntraVerifiedIDClient;
const config = {
tenantId: 'test-tenant-id',
clientId: 'test-client-id',
clientSecret: 'test-client-secret',
credentialManifestId: 'default-manifest-id',
manifests: {
default: 'default-manifest-id',
diplomatic: 'diplomatic-manifest-id',
judicial: 'judicial-manifest-id',
},
};
beforeEach(() => {
client = new EnhancedEntraVerifiedIDClient(config);
vi.clearAllMocks();
});
describe('multi-manifest support', () => {
it('should use default manifest when no manifest name provided', async () => {
const mockTokenResponse = {
access_token: 'test-token',
expires_in: 3600,
};
const mockIssuanceResponse = {
requestId: 'test-request-id',
url: 'https://verifiedid.did.msidentity.com/issuance',
expiry: Date.now() + 3600000,
};
(fetch as any)
.mockResolvedValueOnce({
ok: true,
json: async () => mockTokenResponse,
})
.mockResolvedValueOnce({
ok: true,
json: async () => mockIssuanceResponse,
});
const request: VerifiableCredentialRequest = {
claims: { email: 'test@example.com' },
};
await client.issueCredential(request);
// Verify the request used default manifest
const fetchCalls = (fetch as any).mock.calls;
const issuanceCall = fetchCalls.find((call: any[]) =>
call[0]?.includes('createIssuanceRequest')
);
expect(issuanceCall).toBeDefined();
});
it('should use specified manifest when manifest name provided', async () => {
const mockTokenResponse = {
access_token: 'test-token',
expires_in: 3600,
};
const mockIssuanceResponse = {
requestId: 'test-request-id',
url: 'https://verifiedid.did.msidentity.com/issuance',
expiry: Date.now() + 3600000,
};
(fetch as any)
.mockResolvedValueOnce({
ok: true,
json: async () => mockTokenResponse,
})
.mockResolvedValueOnce({
ok: true,
json: async () => mockIssuanceResponse,
});
const request: VerifiableCredentialRequest & { manifestName?: string } = {
claims: { email: 'test@example.com' },
manifestName: 'diplomatic',
};
await client.issueCredential(request);
// Verify the request used diplomatic manifest
const fetchCalls = (fetch as any).mock.calls;
const issuanceCall = fetchCalls.find((call: any[]) =>
call[0]?.includes('createIssuanceRequest')
);
expect(issuanceCall).toBeDefined();
});
it('should allow registering new manifests', () => {
client.registerManifest('financial', 'financial-manifest-id');
const manifests = client.getManifests();
expect(manifests.financial).toBe('financial-manifest-id');
});
});
describe('retry logic', () => {
it('should retry on retryable errors', async () => {
const mockTokenResponse = {
access_token: 'test-token',
expires_in: 3600,
};
// First two calls fail with 500, third succeeds
(fetch as any)
.mockResolvedValueOnce({
ok: true,
json: async () => mockTokenResponse,
})
.mockResolvedValueOnce({
ok: false,
status: 500,
text: async () => 'Internal Server Error',
})
.mockResolvedValueOnce({
ok: true,
json: async () => mockTokenResponse,
})
.mockResolvedValueOnce({
ok: true,
json: async () => ({
requestId: 'test-request-id',
url: 'https://verifiedid.did.msidentity.com/issuance',
expiry: Date.now() + 3600000,
}),
});
const request: VerifiableCredentialRequest = {
claims: { email: 'test@example.com' },
};
const result = await client.issueCredential(request);
expect(result.requestId).toBe('test-request-id');
// Should have retried (more than 2 fetch calls)
expect(fetch).toHaveBeenCalledTimes(4);
});
it('should not retry on non-retryable errors', async () => {
const mockTokenResponse = {
access_token: 'test-token',
expires_in: 3600,
};
(fetch as any)
.mockResolvedValueOnce({
ok: true,
json: async () => mockTokenResponse,
})
.mockResolvedValueOnce({
ok: false,
status: 400,
text: async () => 'Bad Request',
});
const request: VerifiableCredentialRequest = {
claims: { email: 'test@example.com' },
};
await expect(client.issueCredential(request)).rejects.toThrow();
// Should not retry (only 2 fetch calls)
expect(fetch).toHaveBeenCalledTimes(2);
});
});
});

View File

@@ -4,7 +4,6 @@
*/
import fetch from 'node-fetch';
import { validateBase64File, FileValidationOptions, FILE_SIZE_LIMITS } from './file-utils';
export interface EntraVerifiedIDConfig {
tenantId: string;
@@ -12,6 +11,9 @@ export interface EntraVerifiedIDConfig {
clientSecret: string;
credentialManifestId?: string;
apiVersion?: string;
logoUri?: string; // URI to credential logo/image (PNG, JPG, BMP recommended; SVG may work)
backgroundColor?: string; // Background color for credential card
textColor?: string; // Text color for credential card
}
/**
@@ -111,7 +113,8 @@ export class EntraVerifiedIDClient {
this.accessToken = tokenData.access_token;
// Set expiry 5 minutes before actual expiry for safety
this.tokenExpiry = Date.now() + (tokenData.expires_in - 300) * 1000;
const expiresIn = typeof tokenData.expires_in === 'number' ? tokenData.expires_in : 3600;
this.tokenExpiry = Date.now() + (expiresIn - 300) * 1000;
return this.accessToken;
}
@@ -186,7 +189,7 @@ export class EntraVerifiedIDClient {
}
}
const requestBody = {
const requestBody: Record<string, unknown> = {
includeQRCode: true,
callback: request.callbackUrl
? {
@@ -209,6 +212,15 @@ export class EntraVerifiedIDClient {
claims: stringClaims,
};
// Add display properties if configured
if (this.config.logoUri || this.config.backgroundColor || this.config.textColor) {
requestBody.display = {
...(this.config.logoUri && { logo: { uri: this.config.logoUri } }),
...(this.config.backgroundColor && { backgroundColor: this.config.backgroundColor }),
...(this.config.textColor && { textColor: this.config.textColor }),
};
}
const response = await fetch(issueUrl, {
method: 'POST',
headers: {

View File

@@ -108,7 +108,7 @@ export function encodeFileToBase64(
export function decodeBase64ToBuffer(base64: string): Buffer {
// Remove data URL prefix if present
const base64Data = base64.includes(',')
? base64.split(',')[1]
? (base64.split(',')[1] ?? base64)
: base64;
return Buffer.from(base64Data, 'base64');
@@ -124,7 +124,7 @@ export function isBase64(str: string): boolean {
// Remove data URL prefix if present
const base64Data = str.includes(',')
? str.split(',')[1]
? (str.split(',')[1] ?? str)
: str;
// Base64 regex pattern
@@ -292,7 +292,8 @@ export function validateBase64File(
// Detect and validate MIME type
let mimeType: string | undefined;
try {
mimeType = detectMimeTypeFromBuffer(buffer);
const detected = detectMimeTypeFromBuffer(buffer);
mimeType = detected ?? undefined;
} catch {
// MIME type detection failed, but not critical
}

View File

@@ -6,6 +6,8 @@ export * from './oidc';
export * from './did';
export * from './eidas';
export * from './entra-verifiedid';
export * from './entra-verifiedid-enhanced';
export * from './entra-credential-images';
export * from './azure-logic-apps';
export * from './eidas-entra-bridge';
export * from './file-utils';

View File

@@ -13,7 +13,7 @@ export class SignatureService {
constructor(private kms: KMSClient) {}
async sign(data: Buffer, _options: SignatureOptions): Promise<Buffer> {
return this.kms.sign(data);
return await this.kms.sign(data);
}
async verify(
@@ -21,7 +21,7 @@ export class SignatureService {
signature: Buffer,
_options: SignatureOptions
): Promise<boolean> {
return this.kms.verify(data, signature);
return await this.kms.verify(data, signature);
}
async signJSON(data: unknown, options: SignatureOptions): Promise<string> {

41
packages/database/src/audit-search.d.ts vendored Normal file
View File

@@ -0,0 +1,41 @@
/**
* Enhanced audit logging with search capabilities
*/
import type { CredentialAuditLog } from './credential-lifecycle';
export interface AuditSearchFilters {
credentialId?: string;
issuerDid?: string;
subjectDid?: string;
credentialType?: string | string[];
action?: 'issued' | 'revoked' | 'verified' | 'renewed';
performedBy?: string;
startDate?: Date;
endDate?: Date;
ipAddress?: string;
}
export interface AuditSearchResult {
logs: CredentialAuditLog[];
total: number;
page: number;
pageSize: number;
}
/**
* Search audit logs with filters
*/
export declare function searchAuditLogs(filters: AuditSearchFilters, page?: number, pageSize?: number): Promise<AuditSearchResult>;
/**
* Get audit log statistics
*/
export declare function getAuditStatistics(startDate?: Date, endDate?: Date): Promise<{
totalIssuances: number;
totalRevocations: number;
totalVerifications: number;
totalRenewals: number;
byCredentialType: Record<string, number>;
byAction: Record<string, number>;
}>;
/**
* Export audit logs (for compliance/regulatory reporting)
*/
export declare function exportAuditLogs(filters: AuditSearchFilters, format?: 'json' | 'csv'): Promise<string>;
//# sourceMappingURL=audit-search.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"audit-search.d.ts","sourceRoot":"","sources":["audit-search.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AAEjE,MAAM,WAAW,kBAAkB;IACjC,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,cAAc,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IACnC,MAAM,CAAC,EAAE,QAAQ,GAAG,SAAS,GAAG,UAAU,GAAG,SAAS,CAAC;IACvD,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,IAAI,CAAC;IACjB,OAAO,CAAC,EAAE,IAAI,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,kBAAkB,EAAE,CAAC;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED;;GAEG;AACH,wBAAsB,eAAe,CACnC,OAAO,EAAE,kBAAkB,EAC3B,IAAI,SAAI,EACR,QAAQ,SAAK,GACZ,OAAO,CAAC,iBAAiB,CAAC,CA4E5B;AAED;;GAEG;AACH,wBAAsB,kBAAkB,CACtC,SAAS,CAAC,EAAE,IAAI,EAChB,OAAO,CAAC,EAAE,IAAI,GACb,OAAO,CAAC;IACT,cAAc,EAAE,MAAM,CAAC;IACvB,gBAAgB,EAAE,MAAM,CAAC;IACzB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,aAAa,EAAE,MAAM,CAAC;IACtB,gBAAgB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACzC,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAClC,CAAC,CAsDD;AAED;;GAEG;AACH,wBAAsB,eAAe,CACnC,OAAO,EAAE,kBAAkB,EAC3B,MAAM,GAAE,MAAM,GAAG,KAAc,GAC9B,OAAO,CAAC,MAAM,CAAC,CAiCjB"}

View File

@@ -0,0 +1,144 @@
/**
* Enhanced audit logging with search capabilities
*/
import { query } from './client';
/**
* Search audit logs with filters
*/
export async function searchAuditLogs(filters, page = 1, pageSize = 50) {
const conditions = [];
const params = [];
let paramIndex = 1;
if (filters.credentialId) {
conditions.push(`credential_id = $${paramIndex++}`);
params.push(filters.credentialId);
}
if (filters.issuerDid) {
conditions.push(`issuer_did = $${paramIndex++}`);
params.push(filters.issuerDid);
}
if (filters.subjectDid) {
conditions.push(`subject_did = $${paramIndex++}`);
params.push(filters.subjectDid);
}
if (filters.credentialType) {
const types = Array.isArray(filters.credentialType) ? filters.credentialType : [filters.credentialType];
conditions.push(`credential_type && $${paramIndex++}`);
params.push(types);
}
if (filters.action) {
conditions.push(`action = $${paramIndex++}`);
params.push(filters.action);
}
if (filters.performedBy) {
conditions.push(`performed_by = $${paramIndex++}`);
params.push(filters.performedBy);
}
if (filters.startDate) {
conditions.push(`performed_at >= $${paramIndex++}`);
params.push(filters.startDate);
}
if (filters.endDate) {
conditions.push(`performed_at <= $${paramIndex++}`);
params.push(filters.endDate);
}
if (filters.ipAddress) {
conditions.push(`ip_address = $${paramIndex++}`);
params.push(filters.ipAddress);
}
const whereClause = conditions.length > 0 ? `WHERE ${conditions.join(' AND ')}` : '';
const offset = (page - 1) * pageSize;
// Get total count
const countResult = await query(`SELECT COUNT(*) as count FROM credential_issuance_audit ${whereClause}`, params);
const total = parseInt(countResult.rows[0]?.count || '0', 10);
// Get paginated results
const result = await query(`SELECT * FROM credential_issuance_audit
${whereClause}
ORDER BY performed_at DESC
LIMIT $${paramIndex++} OFFSET $${paramIndex++}`, [...params, pageSize, offset]);
return {
logs: result.rows,
total,
page,
pageSize,
};
}
/**
* Get audit log statistics
*/
export async function getAuditStatistics(startDate, endDate) {
const conditions = [];
const params = [];
let paramIndex = 1;
if (startDate) {
conditions.push(`performed_at >= $${paramIndex++}`);
params.push(startDate);
}
if (endDate) {
conditions.push(`performed_at <= $${paramIndex++}`);
params.push(endDate);
}
const whereClause = conditions.length > 0 ? `WHERE ${conditions.join(' AND ')}` : '';
// Get counts by action
const actionResult = await query(`SELECT action, COUNT(*) as count
FROM credential_issuance_audit
${whereClause}
GROUP BY action`, params);
const byAction = {};
actionResult.rows.forEach((row) => {
byAction[row.action] = parseInt(row.count, 10);
});
// Get counts by credential type
const typeResult = await query(`SELECT credential_type, COUNT(*) as count
FROM credential_issuance_audit
${whereClause}
GROUP BY credential_type`, params);
const byCredentialType = {};
typeResult.rows.forEach((row) => {
const types = row.credential_type.join(', ');
byCredentialType[types] = (byCredentialType[types] || 0) + parseInt(row.count, 10);
});
return {
totalIssuances: byAction.issued || 0,
totalRevocations: byAction.revoked || 0,
totalVerifications: byAction.verified || 0,
totalRenewals: byAction.renewed || 0,
byCredentialType,
byAction,
};
}
/**
* Export audit logs (for compliance/regulatory reporting)
*/
export async function exportAuditLogs(filters, format = 'json') {
const result = await searchAuditLogs(filters, 1, 10000); // Large limit for export
if (format === 'csv') {
const headers = [
'id',
'credential_id',
'issuer_did',
'subject_did',
'credential_type',
'action',
'performed_by',
'performed_at',
'ip_address',
'user_agent',
];
const rows = result.logs.map((log) => [
log.id,
log.credential_id,
log.issuer_did,
log.subject_did,
log.credential_type.join(';'),
log.action,
log.performed_by || '',
log.performed_at.toISOString(),
log.ip_address || '',
log.user_agent || '',
]);
return [headers.join(','), ...rows.map((row) => row.join(','))].join('\n');
}
return JSON.stringify(result.logs, null, 2);
}
//# sourceMappingURL=audit-search.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"audit-search.js","sourceRoot":"","sources":["audit-search.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,KAAK,EAAE,MAAM,UAAU,CAAC;AAsBjC;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe,CACnC,OAA2B,EAC3B,IAAI,GAAG,CAAC,EACR,QAAQ,GAAG,EAAE;IAEb,MAAM,UAAU,GAAa,EAAE,CAAC;IAChC,MAAM,MAAM,GAAc,EAAE,CAAC;IAC7B,IAAI,UAAU,GAAG,CAAC,CAAC;IAEnB,IAAI,OAAO,CAAC,YAAY,EAAE,CAAC;QACzB,UAAU,CAAC,IAAI,CAAC,oBAAoB,UAAU,EAAE,EAAE,CAAC,CAAC;QACpD,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC;IACpC,CAAC;IAED,IAAI,OAAO,CAAC,SAAS,EAAE,CAAC;QACtB,UAAU,CAAC,IAAI,CAAC,iBAAiB,UAAU,EAAE,EAAE,CAAC,CAAC;QACjD,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IACjC,CAAC;IAED,IAAI,OAAO,CAAC,UAAU,EAAE,CAAC;QACvB,UAAU,CAAC,IAAI,CAAC,kBAAkB,UAAU,EAAE,EAAE,CAAC,CAAC;QAClD,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;IAClC,CAAC;IAED,IAAI,OAAO,CAAC,cAAc,EAAE,CAAC;QAC3B,MAAM,KAAK,GAAG,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,cAAc,CAAC,CAAC;QACxG,UAAU,CAAC,IAAI,CAAC,uBAAuB,UAAU,EAAE,EAAE,CAAC,CAAC;QACvD,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACrB,CAAC;IAED,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;QACnB,UAAU,CAAC,IAAI,CAAC,aAAa,UAAU,EAAE,EAAE,CAAC,CAAC;QAC7C,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;IAC9B,CAAC;IAED,IAAI,OAAO,CAAC,WAAW,EAAE,CAAC;QACxB,UAAU,CAAC,IAAI,CAAC,mBAAmB,UAAU,EAAE,EAAE,CAAC,CAAC;QACnD,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC;IACnC,CAAC;IAED,IAAI,OAAO,CAAC,SAAS,EAAE,CAAC;QACtB,UAAU,CAAC,IAAI,CAAC,oBAAoB,UAAU,EAAE,EAAE,CAAC,CAAC;QACpD,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IACjC,CAAC;IAED,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC;QACpB,UAAU,CAAC,IAAI,CAAC,oBAAoB,UAAU,EAAE,EAAE,CAAC,CAAC;QACpD,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;IAC/B,CAAC;IAED,IAAI,OAAO,CAAC,SAAS,EAAE,CAAC;QACtB,UAAU,CAAC,IAAI,CAAC,iBAAiB,UAAU,EAAE,EAAE,CAAC,CAAC;QACjD,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IACjC,CAAC;IAED,MAAM,WAAW,GAAG,UAAU,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS,UAAU,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;IACrF,MAAM,MAAM,GAAG,CAAC,IAAI,GAAG,CAAC,CAAC,GAAG,QAAQ,CAAC;IAErC,kBAAkB;IAClB,MAAM,WAAW,GAAG,MAAM,KAAK,CAC7B,2DAA2D,WAAW,EAAE,EACxE,MAAM,CACP,CAAC;IACF,MAAM,KAAK,GAAG,QAAQ,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,KAAK,IAAI,GAAG,EAAE,EAAE,CAAC,CAAC;IAE9D,wBAAwB;IACxB,MAAM,MAAM,GAAG,MAAM,KAAK,CACxB;OACG,WAAW;;cAEJ,UAAU,EAAE,YAAY,UAAU,EAAE,EAAE,EAChD,CAAC,GAAG,MAAM,EAAE,QAAQ,EAAE,MAAM,CAAC,CAC9B,CAAC;IAEF,OAAO;QACL,IAAI,EAAE,MAAM,CAAC,IAAI;QACjB,KAAK;QACL,IAAI;QACJ,QAAQ;KACT,CAAC;AACJ,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,kBAAkB,CACtC,SAAgB,EAChB,OAAc;IASd,MAAM,UAAU,GAAa,EAAE,CAAC;IAChC,MAAM,MAAM,GAAc,EAAE,CAAC;IAC7B,IAAI,UAAU,GAAG,CAAC,CAAC;IAEnB,IAAI,SAAS,EAAE,CAAC;QACd,UAAU,CAAC,IAAI,CAAC,oBAAoB,UAAU,EAAE,EAAE,CAAC,CAAC;QACpD,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;IACzB,CAAC;IAED,IAAI,OAAO,EAAE,CAAC;QACZ,UAAU,CAAC,IAAI,CAAC,oBAAoB,UAAU,EAAE,EAAE,CAAC,CAAC;QACpD,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IACvB,CAAC;IAED,MAAM,WAAW,GAAG,UAAU,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS,UAAU,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;IAErF,uBAAuB;IACvB,MAAM,YAAY,GAAG,MAAM,KAAK,CAC9B;;OAEG,WAAW;qBACG,EACjB,MAAM,CACP,CAAC;IAEF,MAAM,QAAQ,GAA2B,EAAE,CAAC;IAC5C,YAAY,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,GAAG,EAAE,EAAE;QAChC,QAAQ,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,QAAQ,CAAC,GAAG,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;IACjD,CAAC,CAAC,CAAC;IAEH,gCAAgC;IAChC,MAAM,UAAU,GAAG,MAAM,KAAK,CAC5B;;OAEG,WAAW;8BACY,EAC1B,MAAM,CACP,CAAC;IAEF,MAAM,gBAAgB,GAA2B,EAAE,CAAC;IACpD,UAAU,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,GAAG,EAAE,EAAE;QAC9B,MAAM,KAAK,GAAG,GAAG,CAAC,eAAe,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC7C,gBAAgB,CAAC,KAAK,CAAC,GAAG,CAAC,gBAAgB,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,GAAG,QAAQ,CAAC,GAAG,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;IACrF,CAAC,CAAC,CAAC;IAEH,OAAO;QACL,cAAc,EAAE,QAAQ,CAAC,MAAM,IAAI,CAAC;QACpC,gBAAgB,EAAE,QAAQ,CAAC,OAAO,IAAI,CAAC;QACvC,kBAAkB,EAAE,QAAQ,CAAC,QAAQ,IAAI,CAAC;QAC1C,aAAa,EAAE,QAAQ,CAAC,OAAO,IAAI,CAAC;QACpC,gBAAgB;QAChB,QAAQ;KACT,CAAC;AACJ,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe,CACnC,OAA2B,EAC3B,SAAyB,MAAM;IAE/B,MAAM,MAAM,GAAG,MAAM,eAAe,CAAC,OAAO,EAAE,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC,yBAAyB;IAElF,IAAI,MAAM,KAAK,KAAK,EAAE,CAAC;QACrB,MAAM,OAAO,GAAG;YACd,IAAI;YACJ,eAAe;YACf,YAAY;YACZ,aAAa;YACb,iBAAiB;YACjB,QAAQ;YACR,cAAc;YACd,cAAc;YACd,YAAY;YACZ,YAAY;SACb,CAAC;QACF,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC;YACpC,GAAG,CAAC,EAAE;YACN,GAAG,CAAC,aAAa;YACjB,GAAG,CAAC,UAAU;YACd,GAAG,CAAC,WAAW;YACf,GAAG,CAAC,eAAe,CAAC,IAAI,CAAC,GAAG,CAAC;YAC7B,GAAG,CAAC,MAAM;YACV,GAAG,CAAC,YAAY,IAAI,EAAE;YACtB,GAAG,CAAC,YAAY,CAAC,WAAW,EAAE;YAC9B,GAAG,CAAC,UAAU,IAAI,EAAE;YACpB,GAAG,CAAC,UAAU,IAAI,EAAE;SACrB,CAAC,CAAC;QAEH,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC7E,CAAC;IAED,OAAO,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;AAC9C,CAAC"}

View File

@@ -2,6 +2,7 @@
* PostgreSQL database client with connection pooling
*/
import { Pool, QueryResult, QueryResultRow } from 'pg';
export type { QueryResult, QueryResultRow };
export interface DatabaseConfig {
connectionString?: string;
host?: string;

View File

@@ -1 +1 @@
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["client.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,IAAI,EAAc,WAAW,EAAE,cAAc,EAAE,MAAM,IAAI,CAAC;AAEnE,MAAM,WAAW,cAAc;IAC7B,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,uBAAuB,CAAC,EAAE,MAAM,CAAC;CAClC;AAED;;GAEG;AACH,wBAAgB,UAAU,CAAC,MAAM,EAAE,cAAc,GAAG,IAAI,CAcvD;AAOD;;GAEG;AACH,wBAAgB,OAAO,CAAC,MAAM,CAAC,EAAE,cAAc,GAAG,IAAI,CAQrD;AAED;;GAEG;AACH,wBAAsB,KAAK,CAAC,CAAC,SAAS,cAAc,GAAG,cAAc,EACnE,IAAI,EAAE,MAAM,EACZ,MAAM,CAAC,EAAE,OAAO,EAAE,GACjB,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAKzB;AAED;;GAEG;AACH,wBAAsB,SAAS,IAAI,OAAO,CAAC,IAAI,CAAC,CAK/C;AAED;;GAEG;AACH,wBAAsB,WAAW,IAAI,OAAO,CAAC,OAAO,CAAC,CAQpD"}
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["client.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,IAAI,EAAc,WAAW,EAAE,cAAc,EAAE,MAAM,IAAI,CAAC;AAGnE,YAAY,EAAE,WAAW,EAAE,cAAc,EAAE,CAAC;AAE5C,MAAM,WAAW,cAAc;IAC7B,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,uBAAuB,CAAC,EAAE,MAAM,CAAC;CAClC;AAED;;GAEG;AACH,wBAAgB,UAAU,CAAC,MAAM,EAAE,cAAc,GAAG,IAAI,CAcvD;AAOD;;GAEG;AACH,wBAAgB,OAAO,CAAC,MAAM,CAAC,EAAE,cAAc,GAAG,IAAI,CAQrD;AAED;;GAEG;AACH,wBAAsB,KAAK,CAAC,CAAC,SAAS,cAAc,GAAG,cAAc,EACnE,IAAI,EAAE,MAAM,EACZ,MAAM,CAAC,EAAE,OAAO,EAAE,GACjB,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAKzB;AAED;;GAEG;AACH,wBAAsB,SAAS,IAAI,OAAO,CAAC,IAAI,CAAC,CAK/C;AAED;;GAEG;AACH,wBAAsB,WAAW,IAAI,OAAO,CAAC,OAAO,CAAC,CAQpD"}

View File

@@ -1 +1 @@
{"version":3,"file":"client.js","sourceRoot":"","sources":["client.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,IAAI,EAA2C,MAAM,IAAI,CAAC;AAcnE;;GAEG;AACH,MAAM,UAAU,UAAU,CAAC,MAAsB;IAC/C,MAAM,UAAU,GAAe;QAC7B,gBAAgB,EAAE,MAAM,CAAC,gBAAgB;QACzC,IAAI,EAAE,MAAM,CAAC,IAAI;QACjB,IAAI,EAAE,MAAM,CAAC,IAAI;QACjB,QAAQ,EAAE,MAAM,CAAC,QAAQ;QACzB,IAAI,EAAE,MAAM,CAAC,IAAI;QACjB,QAAQ,EAAE,MAAM,CAAC,QAAQ;QACzB,GAAG,EAAE,MAAM,CAAC,GAAG,IAAI,EAAE;QACrB,iBAAiB,EAAE,MAAM,CAAC,iBAAiB,IAAI,KAAK;QACpD,uBAAuB,EAAE,MAAM,CAAC,uBAAuB,IAAI,IAAI;KAChE,CAAC;IAEF,OAAO,IAAI,IAAI,CAAC,UAAU,CAAC,CAAC;AAC9B,CAAC;AAED;;GAEG;AACH,IAAI,WAAW,GAAgB,IAAI,CAAC;AAEpC;;GAEG;AACH,MAAM,UAAU,OAAO,CAAC,MAAuB;IAC7C,IAAI,CAAC,WAAW,EAAE,CAAC;QACjB,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,MAAM,IAAI,KAAK,CAAC,yDAAyD,CAAC,CAAC;QAC7E,CAAC;QACD,WAAW,GAAG,UAAU,CAAC,MAAM,CAAC,CAAC;IACnC,CAAC;IACD,OAAO,WAAW,CAAC;AACrB,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,KAAK,CACzB,IAAY,EACZ,MAAkB;IAElB,IAAI,CAAC,WAAW,EAAE,CAAC;QACjB,MAAM,IAAI,KAAK,CAAC,yEAAyE,CAAC,CAAC;IAC7F,CAAC;IACD,OAAO,WAAW,CAAC,KAAK,CAAI,IAAI,EAAE,MAAM,CAAC,CAAC;AAC5C,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,SAAS;IAC7B,IAAI,WAAW,EAAE,CAAC;QAChB,MAAM,WAAW,CAAC,GAAG,EAAE,CAAC;QACxB,WAAW,GAAG,IAAI,CAAC;IACrB,CAAC;AACH,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,WAAW;IAC/B,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,OAAO,EAAE,CAAC;QACvB,MAAM,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;QAC7B,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC"}
{"version":3,"file":"client.js","sourceRoot":"","sources":["client.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,IAAI,EAA2C,MAAM,IAAI,CAAC;AAiBnE;;GAEG;AACH,MAAM,UAAU,UAAU,CAAC,MAAsB;IAC/C,MAAM,UAAU,GAAe;QAC7B,gBAAgB,EAAE,MAAM,CAAC,gBAAgB;QACzC,IAAI,EAAE,MAAM,CAAC,IAAI;QACjB,IAAI,EAAE,MAAM,CAAC,IAAI;QACjB,QAAQ,EAAE,MAAM,CAAC,QAAQ;QACzB,IAAI,EAAE,MAAM,CAAC,IAAI;QACjB,QAAQ,EAAE,MAAM,CAAC,QAAQ;QACzB,GAAG,EAAE,MAAM,CAAC,GAAG,IAAI,EAAE;QACrB,iBAAiB,EAAE,MAAM,CAAC,iBAAiB,IAAI,KAAK;QACpD,uBAAuB,EAAE,MAAM,CAAC,uBAAuB,IAAI,IAAI;KAChE,CAAC;IAEF,OAAO,IAAI,IAAI,CAAC,UAAU,CAAC,CAAC;AAC9B,CAAC;AAED;;GAEG;AACH,IAAI,WAAW,GAAgB,IAAI,CAAC;AAEpC;;GAEG;AACH,MAAM,UAAU,OAAO,CAAC,MAAuB;IAC7C,IAAI,CAAC,WAAW,EAAE,CAAC;QACjB,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,MAAM,IAAI,KAAK,CAAC,yDAAyD,CAAC,CAAC;QAC7E,CAAC;QACD,WAAW,GAAG,UAAU,CAAC,MAAM,CAAC,CAAC;IACnC,CAAC;IACD,OAAO,WAAW,CAAC;AACrB,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,KAAK,CACzB,IAAY,EACZ,MAAkB;IAElB,IAAI,CAAC,WAAW,EAAE,CAAC;QACjB,MAAM,IAAI,KAAK,CAAC,yEAAyE,CAAC,CAAC;IAC7F,CAAC;IACD,OAAO,WAAW,CAAC,KAAK,CAAI,IAAI,EAAE,MAAM,CAAC,CAAC;AAC5C,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,SAAS;IAC7B,IAAI,WAAW,EAAE,CAAC;QAChB,MAAM,WAAW,CAAC,GAAG,EAAE,CAAC;QACxB,WAAW,GAAG,IAAI,CAAC;IACrB,CAAC;AACH,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,WAAW;IAC/B,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,OAAO,EAAE,CAAC;QACvB,MAAM,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;QAC7B,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC"}

View File

@@ -0,0 +1,50 @@
/**
* Credential lifecycle management operations
*/
export interface CredentialStatusHistory {
id: string;
credential_id: string;
status: string;
reason?: string;
changed_by?: string;
changed_at: Date;
metadata?: unknown;
}
export interface CredentialRevocation {
id: string;
credential_id: string;
issuer_did: string;
revocation_reason?: string;
revoked_by?: string;
revoked_at: Date;
revocation_list_index?: number;
}
export interface CredentialAuditLog {
id: string;
credential_id: string;
issuer_did: string;
subject_did: string;
credential_type: string[];
action: 'issued' | 'revoked' | 'verified' | 'renewed';
performed_by?: string;
performed_at: Date;
metadata?: unknown;
ip_address?: string;
user_agent?: string;
}
export declare function addCredentialStatusHistory(history: Omit<CredentialStatusHistory, 'id' | 'changed_at'>): Promise<CredentialStatusHistory>;
export declare function getCredentialStatusHistory(credentialId: string): Promise<CredentialStatusHistory[]>;
export declare function revokeCredential(revocation: Omit<CredentialRevocation, 'id' | 'revoked_at' | 'revocation_list_index'>): Promise<CredentialRevocation>;
export declare function isCredentialRevoked(credentialId: string): Promise<boolean>;
export declare function getRevocationRegistry(issuerDid: string, limit?: number, offset?: number): Promise<CredentialRevocation[]>;
export declare function logCredentialAction(audit: Omit<CredentialAuditLog, 'id' | 'performed_at'>): Promise<CredentialAuditLog>;
export declare function getCredentialAuditLog(credentialId: string, limit?: number): Promise<CredentialAuditLog[]>;
export declare function getExpiringCredentials(daysAhead: number, limit?: number): Promise<Array<{
credential_id: string;
expiration_date: Date;
subject_did: string;
issuer_did: string;
credential_type: string[];
credential_subject: unknown;
}>>;
//# sourceMappingURL=credential-lifecycle.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"credential-lifecycle.d.ts","sourceRoot":"","sources":["credential-lifecycle.ts"],"names":[],"mappings":"AAAA;;GAEG;AAIH,MAAM,WAAW,uBAAuB;IACtC,EAAE,EAAE,MAAM,CAAC;IACX,aAAa,EAAE,MAAM,CAAC;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,IAAI,CAAC;IACjB,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,MAAM,WAAW,oBAAoB;IACnC,EAAE,EAAE,MAAM,CAAC;IACX,aAAa,EAAE,MAAM,CAAC;IACtB,UAAU,EAAE,MAAM,CAAC;IACnB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,IAAI,CAAC;IACjB,qBAAqB,CAAC,EAAE,MAAM,CAAC;CAChC;AAED,MAAM,WAAW,kBAAkB;IACjC,EAAE,EAAE,MAAM,CAAC;IACX,aAAa,EAAE,MAAM,CAAC;IACtB,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,eAAe,EAAE,MAAM,EAAE,CAAC;IAC1B,MAAM,EAAE,QAAQ,GAAG,SAAS,GAAG,UAAU,GAAG,SAAS,CAAC;IACtD,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,YAAY,EAAE,IAAI,CAAC;IACnB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAMD,wBAAsB,0BAA0B,CAC9C,OAAO,EAAE,IAAI,CAAC,uBAAuB,EAAE,IAAI,GAAG,YAAY,CAAC,GAC1D,OAAO,CAAC,uBAAuB,CAAC,CAclC;AAED,wBAAsB,0BAA0B,CAC9C,YAAY,EAAE,MAAM,GACnB,OAAO,CAAC,uBAAuB,EAAE,CAAC,CAQpC;AAGD,wBAAsB,gBAAgB,CACpC,UAAU,EAAE,IAAI,CAAC,oBAAoB,EAAE,IAAI,GAAG,YAAY,GAAG,uBAAuB,CAAC,GACpF,OAAO,CAAC,oBAAoB,CAAC,CAiC/B;AAED,wBAAsB,mBAAmB,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAMhF;AAED,wBAAsB,qBAAqB,CACzC,SAAS,EAAE,MAAM,EACjB,KAAK,SAAM,EACX,MAAM,SAAI,GACT,OAAO,CAAC,oBAAoB,EAAE,CAAC,CASjC;AAGD,wBAAsB,mBAAmB,CACvC,KAAK,EAAE,IAAI,CAAC,kBAAkB,EAAE,IAAI,GAAG,cAAc,CAAC,GACrD,OAAO,CAAC,kBAAkB,CAAC,CAmB7B;AAED,wBAAsB,qBAAqB,CACzC,YAAY,EAAE,MAAM,EACpB,KAAK,SAAM,GACV,OAAO,CAAC,kBAAkB,EAAE,CAAC,CAS/B;AAED,wBAAsB,sBAAsB,CAC1C,SAAS,EAAE,MAAM,EACjB,KAAK,SAAM,GACV,OAAO,CAAC,KAAK,CAAC;IAAE,aAAa,EAAE,MAAM,CAAC;IAAC,eAAe,EAAE,IAAI,CAAC;IAAC,WAAW,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAC;IAAC,eAAe,EAAE,MAAM,EAAE,CAAC;IAAC,kBAAkB,EAAE,OAAO,CAAA;CAAE,CAAC,CAAC,CAanK"}

View File

@@ -0,0 +1,97 @@
/**
* Credential lifecycle management operations
*/
import { query } from './client';
// Note: CredentialTemplate operations are now in credential-templates.ts
// This file focuses on lifecycle operations (status history, revocation, audit)
// Credential Status History operations
export async function addCredentialStatusHistory(history) {
const result = await query(`INSERT INTO credential_status_history (credential_id, status, reason, changed_by, metadata)
VALUES ($1, $2, $3, $4, $5)
RETURNING *`, [
history.credential_id,
history.status,
history.reason || null,
history.changed_by || null,
history.metadata ? JSON.stringify(history.metadata) : null,
]);
return result.rows[0];
}
export async function getCredentialStatusHistory(credentialId) {
const result = await query(`SELECT * FROM credential_status_history
WHERE credential_id = $1
ORDER BY changed_at DESC`, [credentialId]);
return result.rows;
}
// Credential Revocation operations
export async function revokeCredential(revocation) {
// First, update the credential as revoked
await query(`UPDATE verifiable_credentials
SET revoked = TRUE, updated_at = NOW()
WHERE credential_id = $1`, [revocation.credential_id]);
// Get the next revocation list index
const indexResult = await query(`SELECT MAX(revocation_list_index) as max_index
FROM credential_revocation_registry
WHERE issuer_did = $1`, [revocation.issuer_did]);
const nextIndex = (indexResult.rows[0]?.max_index ?? -1) + 1;
// Add to revocation registry
const result = await query(`INSERT INTO credential_revocation_registry
(credential_id, issuer_did, revocation_reason, revoked_by, revocation_list_index)
VALUES ($1, $2, $3, $4, $5)
RETURNING *`, [
revocation.credential_id,
revocation.issuer_did,
revocation.revocation_reason || null,
revocation.revoked_by || null,
nextIndex,
]);
return result.rows[0];
}
export async function isCredentialRevoked(credentialId) {
const result = await query(`SELECT revoked FROM verifiable_credentials WHERE credential_id = $1`, [credentialId]);
return result.rows[0]?.revoked ?? false;
}
export async function getRevocationRegistry(issuerDid, limit = 100, offset = 0) {
const result = await query(`SELECT * FROM credential_revocation_registry
WHERE issuer_did = $1
ORDER BY revocation_list_index DESC
LIMIT $2 OFFSET $3`, [issuerDid, limit, offset]);
return result.rows;
}
// Credential Audit Log operations
export async function logCredentialAction(audit) {
const result = await query(`INSERT INTO credential_issuance_audit
(credential_id, issuer_did, subject_did, credential_type, action, performed_by, metadata, ip_address, user_agent)
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)
RETURNING *`, [
audit.credential_id,
audit.issuer_did,
audit.subject_did,
audit.credential_type,
audit.action,
audit.performed_by || null,
audit.metadata ? JSON.stringify(audit.metadata) : null,
audit.ip_address || null,
audit.user_agent || null,
]);
return result.rows[0];
}
export async function getCredentialAuditLog(credentialId, limit = 100) {
const result = await query(`SELECT * FROM credential_issuance_audit
WHERE credential_id = $1
ORDER BY performed_at DESC
LIMIT $2`, [credentialId, limit]);
return result.rows;
}
export async function getExpiringCredentials(daysAhead, limit = 100) {
const result = await query(`SELECT credential_id, expiration_date, subject_did, issuer_did, credential_type, credential_subject
FROM verifiable_credentials
WHERE expiration_date IS NOT NULL
AND expiration_date > NOW()
AND expiration_date < NOW() + INTERVAL '${daysAhead} days'
AND revoked = FALSE
ORDER BY expiration_date ASC
LIMIT $1`, [limit]);
return result.rows;
}
//# sourceMappingURL=credential-lifecycle.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"credential-lifecycle.js","sourceRoot":"","sources":["credential-lifecycle.ts"],"names":[],"mappings":"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"}

View File

@@ -0,0 +1,68 @@
/**
* Credential template management
*/
import { z } from 'zod';
export declare const CredentialTemplateSchema: z.ZodObject<{
id: z.ZodString;
name: z.ZodString;
description: z.ZodOptional<z.ZodString>;
credential_type: z.ZodArray<z.ZodString, "many">;
template_data: z.ZodRecord<z.ZodString, z.ZodUnknown>;
version: z.ZodNumber;
is_active: z.ZodBoolean;
created_by: z.ZodNullable<z.ZodString>;
created_at: z.ZodDate;
updated_at: z.ZodDate;
}, "strip", z.ZodTypeAny, {
name: string;
id: string;
created_at: Date;
updated_at: Date;
created_by: string | null;
credential_type: string[];
template_data: Record<string, unknown>;
version: number;
is_active: boolean;
description?: string | undefined;
}, {
name: string;
id: string;
created_at: Date;
updated_at: Date;
created_by: string | null;
credential_type: string[];
template_data: Record<string, unknown>;
version: number;
is_active: boolean;
description?: string | undefined;
}>;
export type CredentialTemplate = z.infer<typeof CredentialTemplateSchema>;
/**
* Create a credential template
*/
export declare function createCredentialTemplate(template: Omit<CredentialTemplate, 'id' | 'created_at' | 'updated_at'>): Promise<CredentialTemplate>;
/**
* Get credential template by ID
*/
export declare function getCredentialTemplate(id: string): Promise<CredentialTemplate | null>;
/**
* Get credential template by name and version
*/
export declare function getCredentialTemplateByName(name: string, version?: number): Promise<CredentialTemplate | null>;
/**
* List all credential templates
*/
export declare function listCredentialTemplates(activeOnly?: boolean, limit?: number, offset?: number): Promise<CredentialTemplate[]>;
/**
* Update credential template
*/
export declare function updateCredentialTemplate(id: string, updates: Partial<Pick<CredentialTemplate, 'description' | 'template_data' | 'is_active'>>): Promise<CredentialTemplate | null>;
/**
* Create new version of credential template
*/
export declare function createTemplateVersion(templateId: string, updates: Partial<Pick<CredentialTemplate, 'template_data' | 'description'>>): Promise<CredentialTemplate>;
/**
* Render credential from template with variable substitution
*/
export declare function renderCredentialFromTemplate(template: CredentialTemplate, variables: Record<string, unknown>): Record<string, unknown>;
//# sourceMappingURL=credential-templates.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"credential-templates.d.ts","sourceRoot":"","sources":["credential-templates.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,eAAO,MAAM,wBAAwB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAWnC,CAAC;AAEH,MAAM,MAAM,kBAAkB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,wBAAwB,CAAC,CAAC;AAE1E;;GAEG;AACH,wBAAsB,wBAAwB,CAC5C,QAAQ,EAAE,IAAI,CAAC,kBAAkB,EAAE,IAAI,GAAG,YAAY,GAAG,YAAY,CAAC,GACrE,OAAO,CAAC,kBAAkB,CAAC,CAiB7B;AAED;;GAEG;AACH,wBAAsB,qBAAqB,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,kBAAkB,GAAG,IAAI,CAAC,CAM1F;AAED;;GAEG;AACH,wBAAsB,2BAA2B,CAC/C,IAAI,EAAE,MAAM,EACZ,OAAO,CAAC,EAAE,MAAM,GACf,OAAO,CAAC,kBAAkB,GAAG,IAAI,CAAC,CAkBpC;AAED;;GAEG;AACH,wBAAsB,uBAAuB,CAC3C,UAAU,UAAO,EACjB,KAAK,SAAM,EACX,MAAM,SAAI,GACT,OAAO,CAAC,kBAAkB,EAAE,CAAC,CAU/B;AAED;;GAEG;AACH,wBAAsB,wBAAwB,CAC5C,EAAE,EAAE,MAAM,EACV,OAAO,EAAE,OAAO,CAAC,IAAI,CAAC,kBAAkB,EAAE,aAAa,GAAG,eAAe,GAAG,WAAW,CAAC,CAAC,GACxF,OAAO,CAAC,kBAAkB,GAAG,IAAI,CAAC,CAiCpC;AAED;;GAEG;AACH,wBAAsB,qBAAqB,CACzC,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,OAAO,CAAC,IAAI,CAAC,kBAAkB,EAAE,eAAe,GAAG,aAAa,CAAC,CAAC,GAC1E,OAAO,CAAC,kBAAkB,CAAC,CAsB7B;AAED;;GAEG;AACH,wBAAgB,4BAA4B,CAC1C,QAAQ,EAAE,kBAAkB,EAC5B,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GACjC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAsBzB"}

View File

@@ -0,0 +1,148 @@
/**
* Credential template management
*/
import { query } from './client';
import { z } from 'zod';
export const CredentialTemplateSchema = z.object({
id: z.string().uuid(),
name: z.string(),
description: z.string().optional(),
credential_type: z.array(z.string()),
template_data: z.record(z.unknown()),
version: z.number().int().positive(),
is_active: z.boolean(),
created_by: z.string().uuid().nullable(),
created_at: z.date(),
updated_at: z.date(),
});
/**
* Create a credential template
*/
export async function createCredentialTemplate(template) {
const result = await query(`INSERT INTO credential_templates
(name, description, credential_type, template_data, version, is_active, created_by)
VALUES ($1, $2, $3, $4, $5, $6, $7)
RETURNING *`, [
template.name,
template.description || null,
template.credential_type,
JSON.stringify(template.template_data),
template.version,
template.is_active,
template.created_by || null,
]);
return result.rows[0];
}
/**
* Get credential template by ID
*/
export async function getCredentialTemplate(id) {
const result = await query(`SELECT * FROM credential_templates WHERE id = $1`, [id]);
return result.rows[0] || null;
}
/**
* Get credential template by name and version
*/
export async function getCredentialTemplateByName(name, version) {
if (version) {
const result = await query(`SELECT * FROM credential_templates WHERE name = $1 AND version = $2`, [name, version]);
return result.rows[0] || null;
}
else {
// Get latest active version
const result = await query(`SELECT * FROM credential_templates
WHERE name = $1 AND is_active = TRUE
ORDER BY version DESC
LIMIT 1`, [name]);
return result.rows[0] || null;
}
}
/**
* List all credential templates
*/
export async function listCredentialTemplates(activeOnly = true, limit = 100, offset = 0) {
const whereClause = activeOnly ? 'WHERE is_active = TRUE' : '';
const result = await query(`SELECT * FROM credential_templates
${whereClause}
ORDER BY name, version DESC
LIMIT $1 OFFSET $2`, [limit, offset]);
return result.rows;
}
/**
* Update credential template
*/
export async function updateCredentialTemplate(id, updates) {
const fields = [];
const values = [];
let paramIndex = 1;
if (updates.description !== undefined) {
fields.push(`description = $${paramIndex++}`);
values.push(updates.description);
}
if (updates.template_data !== undefined) {
fields.push(`template_data = $${paramIndex++}`);
values.push(JSON.stringify(updates.template_data));
}
if (updates.is_active !== undefined) {
fields.push(`is_active = $${paramIndex++}`);
values.push(updates.is_active);
}
if (fields.length === 0) {
return getCredentialTemplate(id);
}
fields.push(`updated_at = NOW()`);
values.push(id);
const result = await query(`UPDATE credential_templates
SET ${fields.join(', ')}
WHERE id = $${paramIndex}
RETURNING *`, values);
return result.rows[0] || null;
}
/**
* Create new version of credential template
*/
export async function createTemplateVersion(templateId, updates) {
const original = await getCredentialTemplate(templateId);
if (!original) {
throw new Error(`Template ${templateId} not found`);
}
// Get next version number
const versionResult = await query(`SELECT MAX(version) as max_version FROM credential_templates WHERE name = $1`, [original.name]);
const nextVersion = (versionResult.rows[0]?.max_version || 0) + 1;
return createCredentialTemplate({
name: original.name,
description: updates.description || original.description,
credential_type: original.credential_type,
template_data: updates.template_data || original.template_data,
version: nextVersion,
is_active: true,
created_by: original.created_by,
});
}
/**
* Render credential from template with variable substitution
*/
export function renderCredentialFromTemplate(template, variables) {
const rendered = JSON.parse(JSON.stringify(template.template_data));
function substitute(obj) {
if (typeof obj === 'string') {
// Replace {{variable}} patterns
return obj.replace(/\{\{(\w+)\}\}/g, (match, varName) => {
return variables[varName] !== undefined ? String(variables[varName]) : match;
});
}
else if (Array.isArray(obj)) {
return obj.map(substitute);
}
else if (obj && typeof obj === 'object') {
const result = {};
for (const [key, value] of Object.entries(obj)) {
result[key] = substitute(value);
}
return result;
}
return obj;
}
return substitute(rendered);
}
//# sourceMappingURL=credential-templates.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"credential-templates.js","sourceRoot":"","sources":["credential-templates.ts"],"names":[],"mappings":"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"}

View File

@@ -0,0 +1,59 @@
/**
* eResidency Application Database Operations
*/
import { type eResidencyApplication, type eCitizenshipApplication, ApplicationStatus } from '@the-order/schemas';
/**
* Create eResidency application
*/
export declare function createEResidencyApplication(application: Omit<eResidencyApplication, 'id' | 'createdAt' | 'updatedAt'>): Promise<eResidencyApplication>;
/**
* Get eResidency application by ID
*/
export declare function getEResidencyApplicationById(id: string): Promise<eResidencyApplication | null>;
/**
* Update eResidency application
*/
export declare function updateEResidencyApplication(id: string, updates: {
status?: ApplicationStatus;
kycStatus?: 'pending' | 'passed' | 'failed' | 'requires_edd';
sanctionsStatus?: 'pending' | 'clear' | 'flag';
pepStatus?: 'pending' | 'clear' | 'flag';
riskScore?: number;
kycResults?: unknown;
sanctionsResults?: unknown;
riskAssessment?: unknown;
reviewedAt?: string;
reviewedBy?: string;
rejectionReason?: string;
}): Promise<eResidencyApplication>;
/**
* Get review queue
*/
export declare function getReviewQueue(filters: {
riskBand?: 'low' | 'medium' | 'high';
status?: ApplicationStatus;
assignedTo?: string;
limit?: number;
offset?: number;
}): Promise<{
applications: eResidencyApplication[];
total: number;
}>;
/**
* Create eCitizenship application
*/
export declare function createECitizenshipApplication(application: Omit<eCitizenshipApplication, 'id' | 'createdAt' | 'updatedAt'>): Promise<eCitizenshipApplication>;
/**
* Get eCitizenship application by ID
*/
export declare function getECitizenshipApplicationById(id: string): Promise<eCitizenshipApplication | null>;
/**
* Update eCitizenship application
*/
export declare function updateECitizenshipApplication(id: string, updates: {
status?: ApplicationStatus;
reviewedAt?: string;
reviewedBy?: string;
rejectionReason?: string;
}): Promise<eCitizenshipApplication>;
//# sourceMappingURL=eresidency-applications.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"eresidency-applications.d.ts","sourceRoot":"","sources":["eresidency-applications.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,EACL,KAAK,qBAAqB,EAC1B,KAAK,uBAAuB,EAC5B,iBAAiB,EAClB,MAAM,oBAAoB,CAAC;AA4C5B;;GAEG;AACH,wBAAsB,2BAA2B,CAC/C,WAAW,EAAE,IAAI,CAAC,qBAAqB,EAAE,IAAI,GAAG,WAAW,GAAG,WAAW,CAAC,GACzE,OAAO,CAAC,qBAAqB,CAAC,CA2BhC;AAED;;GAEG;AACH,wBAAsB,4BAA4B,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,qBAAqB,GAAG,IAAI,CAAC,CAWpG;AAED;;GAEG;AACH,wBAAsB,2BAA2B,CAC/C,EAAE,EAAE,MAAM,EACV,OAAO,EAAE;IACP,MAAM,CAAC,EAAE,iBAAiB,CAAC;IAC3B,SAAS,CAAC,EAAE,SAAS,GAAG,QAAQ,GAAG,QAAQ,GAAG,cAAc,CAAC;IAC7D,eAAe,CAAC,EAAE,SAAS,GAAG,OAAO,GAAG,MAAM,CAAC;IAC/C,SAAS,CAAC,EAAE,SAAS,GAAG,OAAO,GAAG,MAAM,CAAC;IACzC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B,GACA,OAAO,CAAC,qBAAqB,CAAC,CA2DhC;AAED;;GAEG;AACH,wBAAsB,cAAc,CAAC,OAAO,EAAE;IAC5C,QAAQ,CAAC,EAAE,KAAK,GAAG,QAAQ,GAAG,MAAM,CAAC;IACrC,MAAM,CAAC,EAAE,iBAAiB,CAAC;IAC3B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB,GAAG,OAAO,CAAC;IAAE,YAAY,EAAE,qBAAqB,EAAE,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC,CAkDpE;AAED;;GAEG;AACH,wBAAsB,6BAA6B,CACjD,WAAW,EAAE,IAAI,CAAC,uBAAuB,EAAE,IAAI,GAAG,WAAW,GAAG,WAAW,CAAC,GAC3E,OAAO,CAAC,uBAAuB,CAAC,CAuDlC;AAED;;GAEG;AACH,wBAAsB,8BAA8B,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,uBAAuB,GAAG,IAAI,CAAC,CA6CxG;AAED;;GAEG;AACH,wBAAsB,6BAA6B,CACjD,EAAE,EAAE,MAAM,EACV,OAAO,EAAE;IACP,MAAM,CAAC,EAAE,iBAAiB,CAAC;IAC3B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B,GACA,OAAO,CAAC,uBAAuB,CAAC,CAiElC"}

View File

@@ -0,0 +1,340 @@
/**
* eResidency Application Database Operations
*/
import { query } from './client';
/**
* Map database row to application object
*/
function mapRowToApplication(row) {
return {
id: row.id,
applicantDid: row.applicant_did || undefined,
email: row.email,
givenName: row.given_name,
familyName: row.family_name,
dateOfBirth: row.date_of_birth ? (row.date_of_birth instanceof Date ? row.date_of_birth.toISOString().split('T')[0] : row.date_of_birth) : undefined,
nationality: row.nationality || undefined,
phone: row.phone || undefined,
address: row.address ? (typeof row.address === 'string' ? JSON.parse(row.address) : row.address) : undefined,
deviceFingerprint: row.device_fingerprint || undefined,
identityDocument: row.identity_document
? typeof row.identity_document === 'string'
? JSON.parse(row.identity_document)
: row.identity_document
: undefined,
selfieLiveness: row.selfie_liveness
? typeof row.selfie_liveness === 'string'
? JSON.parse(row.selfie_liveness)
: row.selfie_liveness
: undefined,
status: row.status,
submittedAt: row.submitted_at ? (row.submitted_at instanceof Date ? row.submitted_at.toISOString() : row.submitted_at) : undefined,
reviewedAt: row.reviewed_at ? (row.reviewed_at instanceof Date ? row.reviewed_at.toISOString() : row.reviewed_at) : undefined,
reviewedBy: row.reviewed_by || undefined,
rejectionReason: row.rejection_reason || undefined,
kycStatus: row.kyc_status || undefined,
sanctionsStatus: row.sanctions_status || undefined,
pepStatus: row.pep_status || undefined,
riskScore: row.risk_score ? parseFloat(String(row.risk_score)) : undefined,
kycResults: row.kyc_results ? (typeof row.kyc_results === 'string' ? JSON.parse(row.kyc_results) : row.kyc_results) : undefined,
sanctionsResults: row.sanctions_results ? (typeof row.sanctions_results === 'string' ? JSON.parse(row.sanctions_results) : row.sanctions_results) : undefined,
riskAssessment: row.risk_assessment ? (typeof row.risk_assessment === 'string' ? JSON.parse(row.risk_assessment) : row.risk_assessment) : undefined,
createdAt: row.created_at instanceof Date ? row.created_at.toISOString() : row.created_at,
updatedAt: row.updated_at instanceof Date ? row.updated_at.toISOString() : row.updated_at,
};
}
/**
* Create eResidency application
*/
export async function createEResidencyApplication(application) {
const result = await query(`INSERT INTO eresidency_applications
(applicant_did, email, given_name, family_name, date_of_birth, nationality, phone, address,
device_fingerprint, identity_document, selfie_liveness, status, kyc_status, sanctions_status, pep_status)
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15)
RETURNING *`, [
application.applicantDid || null,
application.email,
application.givenName,
application.familyName,
application.dateOfBirth || null,
application.nationality || null,
application.phone || null,
application.address ? JSON.stringify(application.address) : null,
application.deviceFingerprint || null,
application.identityDocument ? JSON.stringify(application.identityDocument) : null,
application.selfieLiveness ? JSON.stringify(application.selfieLiveness) : null,
application.status,
application.kycStatus || null,
application.sanctionsStatus || null,
application.pepStatus || null,
]);
return mapRowToApplication(result.rows[0]);
}
/**
* Get eResidency application by ID
*/
export async function getEResidencyApplicationById(id) {
const result = await query('SELECT * FROM eresidency_applications WHERE id = $1', [id]);
if (!result.rows[0]) {
return null;
}
return mapRowToApplication(result.rows[0]);
}
/**
* Update eResidency application
*/
export async function updateEResidencyApplication(id, updates) {
const fields = [];
const values = [];
let paramIndex = 1;
if (updates.status !== undefined) {
fields.push(`status = $${paramIndex++}`);
values.push(updates.status);
}
if (updates.kycStatus !== undefined) {
fields.push(`kyc_status = $${paramIndex++}`);
values.push(updates.kycStatus);
}
if (updates.sanctionsStatus !== undefined) {
fields.push(`sanctions_status = $${paramIndex++}`);
values.push(updates.sanctionsStatus);
}
if (updates.pepStatus !== undefined) {
fields.push(`pep_status = $${paramIndex++}`);
values.push(updates.pepStatus);
}
if (updates.riskScore !== undefined) {
fields.push(`risk_score = $${paramIndex++}`);
values.push(updates.riskScore);
}
if (updates.kycResults !== undefined) {
fields.push(`kyc_results = $${paramIndex++}`);
values.push(JSON.stringify(updates.kycResults));
}
if (updates.sanctionsResults !== undefined) {
fields.push(`sanctions_results = $${paramIndex++}`);
values.push(JSON.stringify(updates.sanctionsResults));
}
if (updates.riskAssessment !== undefined) {
fields.push(`risk_assessment = $${paramIndex++}`);
values.push(JSON.stringify(updates.riskAssessment));
}
if (updates.reviewedAt !== undefined) {
fields.push(`reviewed_at = $${paramIndex++}`);
values.push(updates.reviewedAt);
}
if (updates.reviewedBy !== undefined) {
fields.push(`reviewed_by = $${paramIndex++}`);
values.push(updates.reviewedBy);
}
if (updates.rejectionReason !== undefined) {
fields.push(`rejection_reason = $${paramIndex++}`);
values.push(updates.rejectionReason);
}
fields.push(`updated_at = NOW()`);
values.push(id);
const result = await query(`UPDATE eresidency_applications SET ${fields.join(', ')} WHERE id = $${paramIndex} RETURNING *`, values);
return mapRowToApplication(result.rows[0]);
}
/**
* Get review queue
*/
export async function getReviewQueue(filters) {
const conditions = [];
const params = [];
let paramIndex = 1;
if (filters.riskBand) {
// Map risk band to risk score range
const riskRanges = {
low: [0, 0.3],
medium: [0.3, 0.8],
high: [0.8, 1.0],
};
const [min, max] = riskRanges[filters.riskBand];
conditions.push(`risk_score >= $${paramIndex++} AND risk_score < $${paramIndex++}`);
params.push(min, max);
}
if (filters.status) {
conditions.push(`status = $${paramIndex++}`);
params.push(filters.status);
}
if (filters.assignedTo) {
conditions.push(`reviewed_by = $${paramIndex++}`);
params.push(filters.assignedTo);
}
const whereClause = conditions.length > 0 ? `WHERE ${conditions.join(' AND ')}` : '';
const limit = filters.limit || 50;
const offset = filters.offset || 0;
// Get total count
const countResult = await query(`SELECT COUNT(*) as count FROM eresidency_applications ${whereClause}`, params);
const total = parseInt(countResult.rows[0]?.count || '0', 10);
// Get applications
const result = await query(`SELECT * FROM eresidency_applications
${whereClause}
ORDER BY created_at DESC
LIMIT $${paramIndex++} OFFSET $${paramIndex++}`, [...params, limit, offset]);
const applications = result.rows.map((row) => mapRowToApplication(row));
return { applications, total };
}
/**
* Create eCitizenship application
*/
export async function createECitizenshipApplication(application) {
const result = await query(`INSERT INTO ecitizenship_applications
(applicant_did, resident_did, residency_tenure, sponsor_did, service_merit, video_interview,
background_attestations, oath_ceremony, status)
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)
RETURNING *`, [
application.applicantDid,
application.residentDid,
application.residencyTenure,
application.sponsorDid || null,
application.serviceMerit ? JSON.stringify(application.serviceMerit) : null,
application.videoInterview ? JSON.stringify(application.videoInterview) : null,
application.backgroundAttestations ? JSON.stringify(application.backgroundAttestations) : null,
application.oathCeremony ? JSON.stringify(application.oathCeremony) : null,
application.status,
]);
const row = result.rows[0];
return {
id: row.id,
applicantDid: row.applicant_did,
residentDid: row.resident_did,
residencyTenure: row.residency_tenure || undefined,
sponsorDid: row.sponsor_did || undefined,
serviceMerit: row.service_merit
? typeof row.service_merit === 'string'
? JSON.parse(row.service_merit)
: row.service_merit
: undefined,
videoInterview: row.video_interview
? typeof row.video_interview === 'string'
? JSON.parse(row.video_interview)
: row.video_interview
: undefined,
backgroundAttestations: row.background_attestations
? typeof row.background_attestations === 'string'
? JSON.parse(row.background_attestations)
: row.background_attestations
: undefined,
oathCeremony: row.oath_ceremony
? typeof row.oath_ceremony === 'string'
? JSON.parse(row.oath_ceremony)
: row.oath_ceremony
: undefined,
status: row.status,
submittedAt: row.submitted_at ? (row.submitted_at instanceof Date ? row.submitted_at.toISOString() : row.submitted_at) : undefined,
reviewedAt: row.reviewed_at ? (row.reviewed_at instanceof Date ? row.reviewed_at.toISOString() : row.reviewed_at) : undefined,
reviewedBy: row.reviewed_by || undefined,
rejectionReason: row.rejection_reason || undefined,
createdAt: row.created_at instanceof Date ? row.created_at.toISOString() : row.created_at,
updatedAt: row.updated_at instanceof Date ? row.updated_at.toISOString() : row.updated_at,
};
}
/**
* Get eCitizenship application by ID
*/
export async function getECitizenshipApplicationById(id) {
const result = await query('SELECT * FROM ecitizenship_applications WHERE id = $1', [id]);
if (!result.rows[0]) {
return null;
}
const row = result.rows[0];
return {
id: row.id,
applicantDid: row.applicant_did,
residentDid: row.resident_did,
residencyTenure: row.residency_tenure || undefined,
sponsorDid: row.sponsor_did || undefined,
serviceMerit: row.service_merit
? typeof row.service_merit === 'string'
? JSON.parse(row.service_merit)
: row.service_merit
: undefined,
videoInterview: row.video_interview
? typeof row.video_interview === 'string'
? JSON.parse(row.video_interview)
: row.video_interview
: undefined,
backgroundAttestations: row.background_attestations
? typeof row.background_attestations === 'string'
? JSON.parse(row.background_attestations)
: row.background_attestations
: undefined,
oathCeremony: row.oath_ceremony
? typeof row.oath_ceremony === 'string'
? JSON.parse(row.oath_ceremony)
: row.oath_ceremony
: undefined,
status: row.status,
submittedAt: row.submitted_at ? (row.submitted_at instanceof Date ? row.submitted_at.toISOString() : row.submitted_at) : undefined,
reviewedAt: row.reviewed_at ? (row.reviewed_at instanceof Date ? row.reviewed_at.toISOString() : row.reviewed_at) : undefined,
reviewedBy: row.reviewed_by || undefined,
rejectionReason: row.rejection_reason || undefined,
createdAt: row.created_at instanceof Date ? row.created_at.toISOString() : row.created_at,
updatedAt: row.updated_at instanceof Date ? row.updated_at.toISOString() : row.updated_at,
};
}
/**
* Update eCitizenship application
*/
export async function updateECitizenshipApplication(id, updates) {
const fields = [];
const values = [];
let paramIndex = 1;
if (updates.status !== undefined) {
fields.push(`status = $${paramIndex++}`);
values.push(updates.status);
}
if (updates.reviewedAt !== undefined) {
fields.push(`reviewed_at = $${paramIndex++}`);
values.push(updates.reviewedAt);
}
if (updates.reviewedBy !== undefined) {
fields.push(`reviewed_by = $${paramIndex++}`);
values.push(updates.reviewedBy);
}
if (updates.rejectionReason !== undefined) {
fields.push(`rejection_reason = $${paramIndex++}`);
values.push(updates.rejectionReason);
}
fields.push(`updated_at = NOW()`);
values.push(id);
const result = await query(`UPDATE ecitizenship_applications SET ${fields.join(', ')} WHERE id = $${paramIndex} RETURNING *`, values);
const row = result.rows[0];
return {
id: row.id,
applicantDid: row.applicant_did,
residentDid: row.resident_did,
residencyTenure: row.residency_tenure || undefined,
sponsorDid: row.sponsor_did || undefined,
serviceMerit: row.service_merit
? typeof row.service_merit === 'string'
? JSON.parse(row.service_merit)
: row.service_merit
: undefined,
videoInterview: row.video_interview
? typeof row.video_interview === 'string'
? JSON.parse(row.video_interview)
: row.video_interview
: undefined,
backgroundAttestations: row.background_attestations
? typeof row.background_attestations === 'string'
? JSON.parse(row.background_attestations)
: row.background_attestations
: undefined,
oathCeremony: row.oath_ceremony
? typeof row.oath_ceremony === 'string'
? JSON.parse(row.oath_ceremony)
: row.oath_ceremony
: undefined,
status: row.status,
submittedAt: row.submitted_at ? (row.submitted_at instanceof Date ? row.submitted_at.toISOString() : row.submitted_at) : undefined,
reviewedAt: row.reviewed_at ? (row.reviewed_at instanceof Date ? row.reviewed_at.toISOString() : row.reviewed_at) : undefined,
reviewedBy: row.reviewed_by || undefined,
rejectionReason: row.rejection_reason || undefined,
createdAt: row.created_at instanceof Date ? row.created_at.toISOString() : row.created_at,
updatedAt: row.updated_at instanceof Date ? row.updated_at.toISOString() : row.updated_at,
};
}
//# sourceMappingURL=eresidency-applications.js.map

File diff suppressed because one or more lines are too long

View File

@@ -3,5 +3,12 @@
*/
export * from './client';
export * from './schema';
export * from './credential-lifecycle';
export * from './credential-templates';
export * from './audit-search';
export * from './query-cache';
export * from './eresidency-applications';
export { getCredentialTemplateByName, renderCredentialFromTemplate, } from './credential-templates';
export type { QueryResult, QueryResultRow } from './client';
export type { User, Document, Deal, VerifiableCredential, Signature, LedgerEntry, Payment, } from './schema';
//# sourceMappingURL=index.d.ts.map

View File

@@ -1 +1 @@
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,cAAc,UAAU,CAAC;AACzB,cAAc,UAAU,CAAC;AAGzB,YAAY,EACV,IAAI,EACJ,QAAQ,EACR,IAAI,EACJ,oBAAoB,EACpB,SAAS,EACT,WAAW,EACX,OAAO,GACR,MAAM,UAAU,CAAC"}
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,cAAc,UAAU,CAAC;AACzB,cAAc,UAAU,CAAC;AACzB,cAAc,wBAAwB,CAAC;AACvC,cAAc,wBAAwB,CAAC;AACvC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,eAAe,CAAC;AAC9B,cAAc,2BAA2B,CAAC;AAG1C,OAAO,EACL,2BAA2B,EAC3B,4BAA4B,GAC7B,MAAM,wBAAwB,CAAC;AAGhC,YAAY,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AAG5D,YAAY,EACV,IAAI,EACJ,QAAQ,EACR,IAAI,EACJ,oBAAoB,EACpB,SAAS,EACT,WAAW,EACX,OAAO,GACR,MAAM,UAAU,CAAC"}

View File

@@ -3,4 +3,11 @@
*/
export * from './client';
export * from './schema';
export * from './credential-lifecycle';
export * from './credential-templates';
export * from './audit-search';
export * from './query-cache';
export * from './eresidency-applications';
// Re-export template functions for convenience
export { getCredentialTemplateByName, renderCredentialFromTemplate, } from './credential-templates';
//# sourceMappingURL=index.js.map

View File

@@ -1 +1 @@
{"version":3,"file":"index.js","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,cAAc,UAAU,CAAC;AACzB,cAAc,UAAU,CAAC"}
{"version":3,"file":"index.js","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,cAAc,UAAU,CAAC;AACzB,cAAc,UAAU,CAAC;AACzB,cAAc,wBAAwB,CAAC;AACvC,cAAc,wBAAwB,CAAC;AACvC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,eAAe,CAAC;AAC9B,cAAc,2BAA2B,CAAC;AAE1C,+CAA+C;AAC/C,OAAO,EACL,2BAA2B,EAC3B,4BAA4B,GAC7B,MAAM,wBAAwB,CAAC"}

33
packages/database/src/query-cache.d.ts vendored Normal file
View File

@@ -0,0 +1,33 @@
/**
* Database query caching with Redis
* Implements query result caching with automatic invalidation
*
* Note: This module uses optional dynamic import for @the-order/cache
* to avoid requiring it as a direct dependency. If cache is not available,
* queries will execute directly without caching.
*/
import type { QueryResult, QueryResultRow } from './client';
export interface CacheOptions {
ttl?: number;
keyPrefix?: string;
enabled?: boolean;
}
/**
* Execute a query with caching
*/
export declare function cachedQuery<T extends QueryResultRow = QueryResultRow>(sql: string, params?: unknown[], options?: CacheOptions): Promise<QueryResult<T>>;
/**
* Invalidate cache for a pattern
*/
export declare function invalidateCache(pattern: string): Promise<number>;
/**
* Invalidate cache for a specific query
*/
export declare function invalidateQueryCache(sql: string, params?: unknown[]): Promise<void>;
/**
* Cache decorator for database functions
* Note: This is a simplified implementation. In production, you'd need to
* extract SQL and params from the function or pass them as metadata.
*/
export declare function cached<T extends (...args: unknown[]) => Promise<QueryResult<QueryResultRow>>>(fn: T): T;
//# sourceMappingURL=query-cache.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"query-cache.d.ts","sourceRoot":"","sources":["query-cache.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,OAAO,KAAK,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AAE5D,MAAM,WAAW,YAAY;IAC3B,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAuCD;;GAEG;AACH,wBAAsB,WAAW,CAAC,CAAC,SAAS,cAAc,GAAG,cAAc,EACzE,GAAG,EAAE,MAAM,EACX,MAAM,CAAC,EAAE,OAAO,EAAE,EAClB,OAAO,GAAE,YAAiB,GACzB,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CA4BzB;AAED;;GAEG;AACH,wBAAsB,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAMtE;AAED;;GAEG;AACH,wBAAsB,oBAAoB,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAOzF;AAED;;;;GAIG;AACH,wBAAgB,MAAM,CAAC,CAAC,SAAS,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,OAAO,CAAC,WAAW,CAAC,cAAc,CAAC,CAAC,EAC3F,EAAE,EAAE,CAAC,GACJ,CAAC,CAKH"}

View File

@@ -0,0 +1,93 @@
/**
* Database query caching with Redis
* Implements query result caching with automatic invalidation
*
* Note: This module uses optional dynamic import for @the-order/cache
* to avoid requiring it as a direct dependency. If cache is not available,
* queries will execute directly without caching.
*/
import { query } from './client';
// Cache client instance (lazy-loaded via dynamic import)
let cacheClientPromise = null;
/**
* Get cache client (lazy-loaded via dynamic import)
* Returns null if cache module is not available
*/
async function getCacheClient() {
if (cacheClientPromise === null) {
cacheClientPromise = (async () => {
try {
// Use dynamic import with a string literal that TypeScript can't resolve at compile time
// This is done by constructing the import path dynamically
const cacheModulePath = '@the-order/cache';
// eslint-disable-next-line @typescript-eslint/no-implied-eval
const importFunc = new Function('specifier', 'return import(specifier)');
const cacheModule = await importFunc(cacheModulePath);
return cacheModule.getCacheClient();
}
catch {
// Cache module not available - caching will be disabled
return null;
}
})();
}
return cacheClientPromise;
}
/**
* Execute a query with caching
*/
export async function cachedQuery(sql, params, options = {}) {
const { ttl = 3600, keyPrefix = 'db:query:', enabled = true } = options;
if (!enabled) {
return query(sql, params);
}
const cache = await getCacheClient();
if (!cache) {
// Cache not available - execute query directly
return query(sql, params);
}
const cacheKey = `${keyPrefix}${sql}:${JSON.stringify(params || [])}`;
// Try to get from cache
const cached = await cache.get(cacheKey);
if (cached) {
return cached;
}
// Execute query
const result = await query(sql, params);
// Cache result
await cache.set(cacheKey, result, ttl);
return result;
}
/**
* Invalidate cache for a pattern
*/
export async function invalidateCache(pattern) {
const cache = await getCacheClient();
if (!cache) {
return 0;
}
return cache.invalidate(`db:query:${pattern}*`);
}
/**
* Invalidate cache for a specific query
*/
export async function invalidateQueryCache(sql, params) {
const cache = await getCacheClient();
if (!cache) {
return;
}
const cacheKey = `db:query:${sql}:${JSON.stringify(params || [])}`;
await cache.delete(cacheKey);
}
/**
* Cache decorator for database functions
* Note: This is a simplified implementation. In production, you'd need to
* extract SQL and params from the function or pass them as metadata.
*/
export function cached(fn) {
return (async (...args) => {
const result = await fn(...args);
return result;
});
}
//# sourceMappingURL=query-cache.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"query-cache.js","sourceRoot":"","sources":["query-cache.ts"],"names":[],"mappings":"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"}

View File

@@ -11,10 +11,12 @@
"lint": "eslint src --ext .ts",
"type-check": "tsc --noEmit"
},
"dependencies": {},
"dependencies": {
"node-forge": "^1.3.1"
},
"devDependencies": {
"@types/node": "^20.10.6",
"@types/node-forge": "^1.3.11",
"typescript": "^5.3.3"
}
}

View File

@@ -176,7 +176,7 @@ export class BiometricVerifier {
* Calculate image similarity (placeholder)
* In production, use proper image comparison algorithms
*/
private calculateImageSimilarity(image1: Buffer, image2: Buffer): number {
private calculateImageSimilarity(_image1: Buffer, _image2: Buffer): number {
// Placeholder: return random score between 0.5 and 1.0
// In production, use actual image comparison (e.g., perceptual hash, feature matching)
return 0.5 + Math.random() * 0.5;

View File

@@ -199,8 +199,9 @@ export class EUCSCAValidator {
}
}
const checked = this.config.enableCRL || this.config.enableOCSP || false;
return {
checked: this.config.enableCRL || this.config.enableOCSP,
checked,
revoked: false,
};
}
@@ -208,7 +209,7 @@ export class EUCSCAValidator {
/**
* Check Certificate Revocation List (CRL)
*/
private async checkCRL(certificate: X509Certificate): Promise<{
private async checkCRL(_certificate: X509Certificate): Promise<{
checked: boolean;
revoked: boolean;
revocationDate?: Date;
@@ -225,7 +226,7 @@ export class EUCSCAValidator {
/**
* Check Online Certificate Status Protocol (OCSP)
*/
private async checkOCSP(certificate: X509Certificate): Promise<{
private async checkOCSP(_certificate: X509Certificate): Promise<{
checked: boolean;
revoked: boolean;
revocationDate?: Date;

View File

@@ -55,7 +55,10 @@ export interface ChipReadingConfig {
* actual NFC/contactless card reading libraries (e.g., pcsc-lite, nfc-pcsc)
*/
export class EUChipReader {
constructor(private config: ChipReadingConfig = {}) {}
constructor(config: ChipReadingConfig = {}) {
// Config stored for future use
void config;
}
/**
* Establish BAC (Basic Access Control) session
@@ -75,7 +78,7 @@ export class EUChipReader {
/**
* Establish EAC (Extended Access Control) session
*/
async establishEAC(certificate: Buffer): Promise<{ sessionKey: Buffer }> {
async establishEAC(_certificate: Buffer): Promise<{ sessionKey: Buffer }> {
// EAC uses certificate-based authentication
// In production, implement full EAC protocol
const sessionKey = Buffer.alloc(16, 0); // Placeholder
@@ -131,7 +134,7 @@ export class EUChipReader {
/**
* Read specific data group
*/
async readDataGroup(groupNumber: number): Promise<Buffer> {
async readDataGroup(_groupNumber: number): Promise<Buffer> {
// In production, read from chip
return Buffer.alloc(0);
}

View File

@@ -131,7 +131,7 @@ export class SecurityFeatureValidator {
/**
* Check UV (ultraviolet) security features
*/
private async checkUVFeatures(image: Buffer): Promise<{ passed: boolean; details?: string }> {
private async checkUVFeatures(_image: Buffer): Promise<{ passed: boolean; details?: string }> {
// In production, analyze UV image for security features
// EU-LP should have UV-reactive elements (security threads, UV printing)
// For now, return placeholder
@@ -144,7 +144,7 @@ export class SecurityFeatureValidator {
/**
* Check IR (infrared) security features
*/
private async checkIRFeatures(image: Buffer): Promise<{ passed: boolean; details?: string }> {
private async checkIRFeatures(_image: Buffer): Promise<{ passed: boolean; details?: string }> {
// In production, analyze IR image for security features
// EU-LP should have IR-visible security elements
// For now, return placeholder
@@ -157,7 +157,7 @@ export class SecurityFeatureValidator {
/**
* Check watermark
*/
private async checkWatermark(image: Buffer): Promise<{ passed: boolean; details?: string }> {
private async checkWatermark(_image: Buffer): Promise<{ passed: boolean; details?: string }> {
// In production, use image processing to detect watermark
// EU-LP should have a watermark with the EU logo or text
// For now, return placeholder
@@ -170,7 +170,7 @@ export class SecurityFeatureValidator {
/**
* Check OVI (Optically Variable Ink)
*/
private async checkOVI(image: Buffer): Promise<{ passed: boolean; details?: string }> {
private async checkOVI(_image: Buffer): Promise<{ passed: boolean; details?: string }> {
// In production, check for color-shifting ink
// OVI changes color when viewed from different angles
// For now, return placeholder
@@ -183,7 +183,7 @@ export class SecurityFeatureValidator {
/**
* Check intaglio printing
*/
private async checkIntaglioPrinting(image: Buffer): Promise<{ passed: boolean; details?: string }> {
private async checkIntaglioPrinting(_image: Buffer): Promise<{ passed: boolean; details?: string }> {
// In production, detect raised/embossed printing
// Intaglio creates a tactile, raised effect
// For now, return placeholder

View File

@@ -136,7 +136,8 @@ export class JobQueue {
options?: JobsOptions
): Promise<Job<T>> {
const queue = this.queues.get(queueName) || this.createQueue<T>(queueName);
return queue.add('default', data, options);
// eslint-disable-next-line @typescript-eslint/no-explicit-any
return queue.add('default' as any, data as any, options);
}
/**
@@ -149,7 +150,8 @@ export class JobQueue {
options?: JobsOptions
): Promise<Job<T>> {
const queue = this.queues.get(queueName) || this.createQueue<T>(queueName);
return queue.add('default', data, {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
return queue.add('default' as any, data as any, {
...options,
delay: typeof delay === 'number' ? delay : delay.getTime() - Date.now(),
});
@@ -165,7 +167,8 @@ export class JobQueue {
options?: JobsOptions
): Promise<Job<T>> {
const queue = this.queues.get(queueName) || this.createQueue<T>(queueName);
return queue.add('default', data, {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
return queue.add('default' as any, data as any, {
...options,
repeat: {
pattern: cronPattern,

View File

@@ -0,0 +1,150 @@
/**
* Microsoft Entra VerifiedID metrics
* Tracks Entra VerifiedID API usage, success rates, and performance
*/
import { Counter, Histogram, Gauge, register } from 'prom-client';
// Entra API request metrics
export const entraApiRequests = new Counter({
name: 'entra_api_requests_total',
help: 'Total number of Entra VerifiedID API requests',
labelNames: ['operation', 'status'],
registers: [register],
});
export const entraApiRequestDuration = new Histogram({
name: 'entra_api_request_duration_seconds',
help: 'Duration of Entra VerifiedID API requests',
labelNames: ['operation'],
buckets: [0.1, 0.5, 1, 2, 5, 10, 30],
registers: [register],
});
export const entraApiErrors = new Counter({
name: 'entra_api_errors_total',
help: 'Total number of Entra VerifiedID API errors',
labelNames: ['operation', 'error_type', 'status_code'],
registers: [register],
});
// Credential issuance metrics
export const entraCredentialsIssued = new Counter({
name: 'entra_credentials_issued_total',
help: 'Total number of credentials issued via Entra VerifiedID',
labelNames: ['manifest_name', 'status'],
registers: [register],
});
export const entraIssuanceDuration = new Histogram({
name: 'entra_issuance_duration_seconds',
help: 'Time to issue a credential via Entra VerifiedID',
labelNames: ['manifest_name'],
buckets: [0.5, 1, 2, 5, 10, 30, 60],
registers: [register],
});
export const entraIssuanceRetries = new Counter({
name: 'entra_issuance_retries_total',
help: 'Total number of retries for Entra credential issuance',
labelNames: ['manifest_name', 'attempt'],
registers: [register],
});
// Credential verification metrics
export const entraCredentialsVerified = new Counter({
name: 'entra_credentials_verified_total',
help: 'Total number of credentials verified via Entra VerifiedID',
labelNames: ['result'],
registers: [register],
});
export const entraVerificationDuration = new Histogram({
name: 'entra_verification_duration_seconds',
help: 'Time to verify a credential via Entra VerifiedID',
buckets: [0.1, 0.5, 1, 2, 5],
registers: [register],
});
// Status check metrics
export const entraStatusChecks = new Counter({
name: 'entra_status_checks_total',
help: 'Total number of Entra issuance status checks',
labelNames: ['state'],
registers: [register],
});
export const entraStatusCheckDuration = new Histogram({
name: 'entra_status_check_duration_seconds',
help: 'Time to check Entra issuance status',
buckets: [0.1, 0.5, 1, 2, 5],
registers: [register],
});
// Token management metrics
export const entraTokenRefreshes = new Counter({
name: 'entra_token_refreshes_total',
help: 'Total number of Entra access token refreshes',
registers: [register],
});
export const entraTokenCacheHits = new Counter({
name: 'entra_token_cache_hits_total',
help: 'Total number of Entra token cache hits',
registers: [register],
});
export const entraTokenCacheMisses = new Counter({
name: 'entra_token_cache_misses_total',
help: 'Total number of Entra token cache misses',
registers: [register],
});
// Webhook/callback metrics
export const entraWebhooksReceived = new Counter({
name: 'entra_webhooks_received_total',
help: 'Total number of Entra webhooks received',
labelNames: ['event_type', 'status'],
registers: [register],
});
export const entraWebhookProcessingDuration = new Histogram({
name: 'entra_webhook_processing_duration_seconds',
help: 'Time to process an Entra webhook',
labelNames: ['event_type'],
buckets: [0.1, 0.5, 1, 2, 5],
registers: [register],
});
export const entraWebhookErrors = new Counter({
name: 'entra_webhook_errors_total',
help: 'Total number of Entra webhook processing errors',
labelNames: ['event_type', 'error_type'],
registers: [register],
});
// Active requests gauge
export const entraActiveRequests = new Gauge({
name: 'entra_active_requests',
help: 'Number of active Entra API requests',
labelNames: ['operation'],
registers: [register],
});
// Success rate calculation helpers
// Note: This is a helper function - actual success rate should be calculated
// from Prometheus queries like:
// rate(entra_credentials_issued_total{status="success"}[5m]) / rate(entra_credentials_issued_total[5m])
export function getEntraIssuanceSuccessRate(): number {
// This function is a placeholder - actual calculation should be done via Prometheus queries
// as prom-client doesn't expose internal metrics directly
return 0;
}
/**
* Get all Entra metrics in Prometheus format
*/
export async function getEntraMetrics(): Promise<string> {
return register.metrics();
}

View File

@@ -5,4 +5,11 @@
export * from './otel';
export * from './metrics';
export * from './business-metrics';
export * from './entra-metrics';
// Re-export business metrics with explicit names to avoid conflicts
export {
documentsProcessed,
paymentsProcessed,
} from './business-metrics';

View File

@@ -35,21 +35,7 @@ export const dbConnectionsActive = new Gauge({
registers: [register],
});
// Business metrics
export const documentsProcessed = new Counter({
name: 'documents_processed_total',
help: 'Total number of documents processed',
labelNames: ['status', 'classification'],
registers: [register],
});
export const paymentsProcessed = new Counter({
name: 'payments_processed_total',
help: 'Total number of payments processed',
labelNames: ['status', 'currency'],
registers: [register],
});
// Verifiable credentials metrics
export const vcIssued = new Counter({
name: 'verifiable_credentials_issued_total',
help: 'Total number of verifiable credentials issued',

45
packages/ocr/src/client.d.ts vendored Normal file
View File

@@ -0,0 +1,45 @@
/**
* OCR service client
*/
import { StorageClient } from '@the-order/storage';
export interface OCRResult {
text: string;
confidence: number;
words: Array<{
text: string;
confidence: number;
bbox: {
x0: number;
y0: number;
x1: number;
y1: number;
};
}>;
}
export declare class OCRClient {
private storageClient?;
constructor(storageClient?: StorageClient);
/**
* Process document from storage key with retry logic
*/
processFromStorage(storageKey: string, options?: {
maxRetries?: number;
initialDelay?: number;
}): Promise<OCRResult>;
/**
* Process document from buffer with retry logic
*/
processBuffer(buffer: Buffer, options?: {
maxRetries?: number;
initialDelay?: number;
}): Promise<OCRResult>;
/**
* Process with external OCR service
*/
private processWithExternalService;
/**
* Process with local Tesseract.js
*/
private processWithTesseract;
}
//# sourceMappingURL=client.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["client.ts"],"names":[],"mappings":"AAAA;;GAEG;AAIH,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAEnD,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,KAAK,CAAC;QACX,IAAI,EAAE,MAAM,CAAC;QACb,UAAU,EAAE,MAAM,CAAC;QACnB,IAAI,EAAE;YAAE,EAAE,EAAE,MAAM,CAAC;YAAC,EAAE,EAAE,MAAM,CAAC;YAAC,EAAE,EAAE,MAAM,CAAC;YAAC,EAAE,EAAE,MAAM,CAAA;SAAE,CAAC;KAC1D,CAAC,CAAC;CACJ;AAED,qBAAa,SAAS;IACpB,OAAO,CAAC,aAAa,CAAC,CAAgB;gBAE1B,aAAa,CAAC,EAAE,aAAa;IAIzC;;OAEG;IACG,kBAAkB,CACtB,UAAU,EAAE,MAAM,EAClB,OAAO,CAAC,EAAE;QAAE,UAAU,CAAC,EAAE,MAAM,CAAC;QAAC,YAAY,CAAC,EAAE,MAAM,CAAA;KAAE,GACvD,OAAO,CAAC,SAAS,CAAC;IASrB;;OAEG;IACG,aAAa,CACjB,MAAM,EAAE,MAAM,EACd,OAAO,CAAC,EAAE;QAAE,UAAU,CAAC,EAAE,MAAM,CAAC;QAAC,YAAY,CAAC,EAAE,MAAM,CAAA;KAAE,GACvD,OAAO,CAAC,SAAS,CAAC;IAkCrB;;OAEG;YACW,0BAA0B;IAkBxC;;OAEG;YACW,oBAAoB;CAwBnC"}

View File

@@ -0,0 +1,97 @@
/**
* OCR service client
*/
import { createWorker } from 'tesseract.js';
import { getEnv } from '@the-order/shared';
export class OCRClient {
storageClient;
constructor(storageClient) {
this.storageClient = storageClient;
}
/**
* Process document from storage key with retry logic
*/
async processFromStorage(storageKey, options) {
if (!this.storageClient) {
throw new Error('Storage client required for processing from storage');
}
const fileBuffer = await this.storageClient.download(storageKey);
return this.processBuffer(fileBuffer, options);
}
/**
* Process document from buffer with retry logic
*/
async processBuffer(buffer, options) {
const maxRetries = options?.maxRetries ?? 3;
const initialDelay = options?.initialDelay ?? 1000;
let lastError = null;
for (let attempt = 0; attempt < maxRetries; attempt++) {
try {
const env = getEnv();
// Use external OCR service if configured
if (env.OCR_SERVICE_URL) {
return await this.processWithExternalService(buffer);
}
// Fallback to local Tesseract.js
return await this.processWithTesseract(buffer);
}
catch (error) {
lastError = error instanceof Error ? error : new Error(String(error));
// Don't retry on the last attempt
if (attempt === maxRetries - 1) {
throw lastError;
}
// Exponential backoff: delay = initialDelay * 2^attempt
const delay = initialDelay * Math.pow(2, attempt);
await new Promise((resolve) => setTimeout(resolve, delay));
}
}
// This should never be reached, but TypeScript needs it
throw lastError || new Error('OCR processing failed after retries');
}
/**
* Process with external OCR service
*/
async processWithExternalService(buffer) {
const env = getEnv();
const response = await fetch(`${env.OCR_SERVICE_URL}/process`, {
method: 'POST',
headers: {
'Content-Type': 'application/octet-stream',
Authorization: `Bearer ${env.OCR_SERVICE_API_KEY}`,
},
body: buffer,
});
if (!response.ok) {
throw new Error(`OCR service error: ${response.status}`);
}
return (await response.json());
}
/**
* Process with local Tesseract.js
*/
async processWithTesseract(buffer) {
const worker = await createWorker('eng');
try {
const { data } = await worker.recognize(buffer);
return {
text: data.text,
confidence: data.confidence || 0,
words: data.words.map((word) => ({
text: word.text,
confidence: word.confidence || 0,
bbox: {
x0: word.bbox.x0,
y0: word.bbox.y0,
x1: word.bbox.x1,
y1: word.bbox.y1,
},
})),
};
}
finally {
await worker.terminate();
}
}
}
//# sourceMappingURL=client.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"client.js","sourceRoot":"","sources":["client.ts"],"names":[],"mappings":"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"}

5
packages/ocr/src/index.d.ts vendored Normal file
View File

@@ -0,0 +1,5 @@
/**
* OCR service client
*/
export * from './client';
//# sourceMappingURL=index.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,cAAc,UAAU,CAAC"}

View File

@@ -0,0 +1,5 @@
/**
* OCR service client
*/
export * from './client';
//# sourceMappingURL=index.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"index.js","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,cAAc,UAAU,CAAC"}

View File

@@ -8,16 +8,16 @@ export declare const DealSchema: z.ZodObject<{
createdAt: z.ZodUnion<[z.ZodDate, z.ZodString]>;
updatedAt: z.ZodUnion<[z.ZodDate, z.ZodString]>;
}, "strip", z.ZodTypeAny, {
id: string;
status: "draft" | "active" | "closed" | "archived";
name: string;
id: string;
createdAt: string | Date;
updatedAt: string | Date;
dataroomId?: string | undefined;
}, {
id: string;
status: "draft" | "active" | "closed" | "archived";
name: string;
id: string;
createdAt: string | Date;
updatedAt: string | Date;
dataroomId?: string | undefined;

View File

@@ -10,18 +10,18 @@ export declare const DocumentSchema: z.ZodObject<{
updatedAt: z.ZodUnion<[z.ZodDate, z.ZodString]>;
}, "strip", z.ZodTypeAny, {
id: string;
type: "legal" | "treaty" | "finance" | "history";
title: string;
type: "treaty" | "legal" | "finance" | "history";
createdAt: string | Date;
updatedAt: string | Date;
title: string;
content?: string | undefined;
fileUrl?: string | undefined;
}, {
id: string;
type: "legal" | "treaty" | "finance" | "history";
title: string;
type: "treaty" | "legal" | "finance" | "history";
createdAt: string | Date;
updatedAt: string | Date;
title: string;
content?: string | undefined;
fileUrl?: string | undefined;
}>;
@@ -35,13 +35,13 @@ export declare const CreateDocumentSchema: z.ZodObject<Omit<{
createdAt: z.ZodUnion<[z.ZodDate, z.ZodString]>;
updatedAt: z.ZodUnion<[z.ZodDate, z.ZodString]>;
}, "id" | "createdAt" | "updatedAt">, "strip", z.ZodTypeAny, {
type: "legal" | "treaty" | "finance" | "history";
title: string;
type: "treaty" | "legal" | "finance" | "history";
content?: string | undefined;
fileUrl?: string | undefined;
}, {
type: "legal" | "treaty" | "finance" | "history";
title: string;
type: "treaty" | "legal" | "finance" | "history";
content?: string | undefined;
fileUrl?: string | undefined;
}>;

View File

@@ -105,14 +105,14 @@ export declare const evidenceSchema: z.ZodObject<{
result: z.ZodNativeEnum<typeof EvidenceResult>;
timestamp: z.ZodOptional<z.ZodString>;
}, "strip", z.ZodTypeAny, {
type: EvidenceType;
result: EvidenceResult;
type: EvidenceType;
verifier?: string | undefined;
txn?: string | undefined;
timestamp?: string | undefined;
}, {
type: EvidenceType;
result: EvidenceResult;
type: EvidenceType;
verifier?: string | undefined;
txn?: string | undefined;
timestamp?: string | undefined;
@@ -146,7 +146,6 @@ export declare const addressAttestationCredentialSubjectSchema: z.ZodObject<{
attestedUntil: z.ZodOptional<z.ZodString>;
attestedBy: z.ZodString;
}, "strip", z.ZodTypeAny, {
id: string;
address: {
street: string;
city: string;
@@ -154,11 +153,11 @@ export declare const addressAttestationCredentialSubjectSchema: z.ZodObject<{
country: string;
region?: string | undefined;
};
id: string;
attestedSince: string;
attestedBy: string;
attestedUntil?: string | undefined;
}, {
id: string;
address: {
street: string;
city: string;
@@ -166,6 +165,7 @@ export declare const addressAttestationCredentialSubjectSchema: z.ZodObject<{
country: string;
region?: string | undefined;
};
id: string;
attestedSince: string;
attestedBy: string;
attestedUntil?: string | undefined;
@@ -229,21 +229,21 @@ export declare const professionalOrderCredentialSubjectSchema: z.ZodObject<{
credentials: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
status: z.ZodEnum<["active", "suspended", "revoked", "expired"]>;
}, "strip", z.ZodTypeAny, {
id: string;
status: "revoked" | "active" | "suspended" | "expired";
id: string;
order: string;
role: string;
membershipSince: string;
membershipUntil?: string | undefined;
credentials?: string[] | undefined;
membershipUntil?: string | undefined;
}, {
id: string;
status: "revoked" | "active" | "suspended" | "expired";
id: string;
order: string;
role: string;
membershipSince: string;
membershipUntil?: string | undefined;
credentials?: string[] | undefined;
membershipUntil?: string | undefined;
}>;
export type ProfessionalOrderCredentialSubject = z.infer<typeof professionalOrderCredentialSubjectSchema>;
/**
@@ -295,14 +295,14 @@ export declare const eResidentCredentialSchema: z.ZodObject<{
result: z.ZodNativeEnum<typeof EvidenceResult>;
timestamp: z.ZodOptional<z.ZodString>;
}, "strip", z.ZodTypeAny, {
type: EvidenceType;
result: EvidenceResult;
type: EvidenceType;
verifier?: string | undefined;
txn?: string | undefined;
timestamp?: string | undefined;
}, {
type: EvidenceType;
result: EvidenceResult;
type: EvidenceType;
verifier?: string | undefined;
txn?: string | undefined;
timestamp?: string | undefined;
@@ -328,6 +328,13 @@ export declare const eResidentCredentialSchema: z.ZodObject<{
}>;
}, "strip", z.ZodTypeAny, {
type: string[];
proof: {
type: string;
created: string;
proofPurpose: string;
verificationMethod: string;
jws?: string | undefined;
};
issuer: string;
credentialSubject: {
id: string;
@@ -338,13 +345,6 @@ export declare const eResidentCredentialSchema: z.ZodObject<{
publicHandle?: string | undefined;
};
issuanceDate: string;
proof: {
type: string;
created: string;
proofPurpose: string;
verificationMethod: string;
jws?: string | undefined;
};
'@context': string[];
expirationDate?: string | undefined;
credentialStatus?: {
@@ -352,14 +352,21 @@ export declare const eResidentCredentialSchema: z.ZodObject<{
type: string;
} | undefined;
evidence?: {
type: EvidenceType;
result: EvidenceResult;
type: EvidenceType;
verifier?: string | undefined;
txn?: string | undefined;
timestamp?: string | undefined;
}[] | undefined;
}, {
type: string[];
proof: {
type: string;
created: string;
proofPurpose: string;
verificationMethod: string;
jws?: string | undefined;
};
issuer: string;
credentialSubject: {
id: string;
@@ -370,13 +377,6 @@ export declare const eResidentCredentialSchema: z.ZodObject<{
publicHandle?: string | undefined;
};
issuanceDate: string;
proof: {
type: string;
created: string;
proofPurpose: string;
verificationMethod: string;
jws?: string | undefined;
};
'@context': string[];
expirationDate?: string | undefined;
credentialStatus?: {
@@ -384,8 +384,8 @@ export declare const eResidentCredentialSchema: z.ZodObject<{
type: string;
} | undefined;
evidence?: {
type: EvidenceType;
result: EvidenceResult;
type: EvidenceType;
verifier?: string | undefined;
txn?: string | undefined;
timestamp?: string | undefined;
@@ -441,14 +441,14 @@ export declare const eCitizenCredentialSchema: z.ZodObject<{
result: z.ZodNativeEnum<typeof EvidenceResult>;
timestamp: z.ZodOptional<z.ZodString>;
}, "strip", z.ZodTypeAny, {
type: EvidenceType;
result: EvidenceResult;
type: EvidenceType;
verifier?: string | undefined;
txn?: string | undefined;
timestamp?: string | undefined;
}, {
type: EvidenceType;
result: EvidenceResult;
type: EvidenceType;
verifier?: string | undefined;
txn?: string | undefined;
timestamp?: string | undefined;
@@ -474,6 +474,13 @@ export declare const eCitizenCredentialSchema: z.ZodObject<{
}>;
}, "strip", z.ZodTypeAny, {
type: string[];
proof: {
type: string;
created: string;
proofPurpose: string;
verificationMethod: string;
jws?: string | undefined;
};
issuer: string;
credentialSubject: {
id: string;
@@ -484,13 +491,6 @@ export declare const eCitizenCredentialSchema: z.ZodObject<{
sponsoringMember?: string | undefined;
};
issuanceDate: string;
proof: {
type: string;
created: string;
proofPurpose: string;
verificationMethod: string;
jws?: string | undefined;
};
'@context': string[];
expirationDate?: string | undefined;
credentialStatus?: {
@@ -498,14 +498,21 @@ export declare const eCitizenCredentialSchema: z.ZodObject<{
type: string;
} | undefined;
evidence?: {
type: EvidenceType;
result: EvidenceResult;
type: EvidenceType;
verifier?: string | undefined;
txn?: string | undefined;
timestamp?: string | undefined;
}[] | undefined;
}, {
type: string[];
proof: {
type: string;
created: string;
proofPurpose: string;
verificationMethod: string;
jws?: string | undefined;
};
issuer: string;
credentialSubject: {
id: string;
@@ -516,13 +523,6 @@ export declare const eCitizenCredentialSchema: z.ZodObject<{
sponsoringMember?: string | undefined;
};
issuanceDate: string;
proof: {
type: string;
created: string;
proofPurpose: string;
verificationMethod: string;
jws?: string | undefined;
};
'@context': string[];
expirationDate?: string | undefined;
credentialStatus?: {
@@ -530,8 +530,8 @@ export declare const eCitizenCredentialSchema: z.ZodObject<{
type: string;
} | undefined;
evidence?: {
type: EvidenceType;
result: EvidenceResult;
type: EvidenceType;
verifier?: string | undefined;
txn?: string | undefined;
timestamp?: string | undefined;
@@ -543,7 +543,7 @@ export type eCitizenCredential = z.infer<typeof eCitizenCredentialSchema>;
*/
export declare const verifiablePresentationSchema: z.ZodObject<{
'@context': z.ZodArray<z.ZodString, "many">;
type: any;
type: z.ZodEffects<z.ZodArray<z.ZodString, "many">, string[], string[]>;
verifiableCredential: z.ZodArray<z.ZodUnion<[z.ZodObject<{
'@context': z.ZodArray<z.ZodString, "many">;
type: z.ZodEffects<z.ZodArray<z.ZodString, "many">, string[], string[]>;
@@ -589,14 +589,14 @@ export declare const verifiablePresentationSchema: z.ZodObject<{
result: z.ZodNativeEnum<typeof EvidenceResult>;
timestamp: z.ZodOptional<z.ZodString>;
}, "strip", z.ZodTypeAny, {
type: EvidenceType;
result: EvidenceResult;
type: EvidenceType;
verifier?: string | undefined;
txn?: string | undefined;
timestamp?: string | undefined;
}, {
type: EvidenceType;
result: EvidenceResult;
type: EvidenceType;
verifier?: string | undefined;
txn?: string | undefined;
timestamp?: string | undefined;
@@ -622,6 +622,13 @@ export declare const verifiablePresentationSchema: z.ZodObject<{
}>;
}, "strip", z.ZodTypeAny, {
type: string[];
proof: {
type: string;
created: string;
proofPurpose: string;
verificationMethod: string;
jws?: string | undefined;
};
issuer: string;
credentialSubject: {
id: string;
@@ -632,13 +639,6 @@ export declare const verifiablePresentationSchema: z.ZodObject<{
publicHandle?: string | undefined;
};
issuanceDate: string;
proof: {
type: string;
created: string;
proofPurpose: string;
verificationMethod: string;
jws?: string | undefined;
};
'@context': string[];
expirationDate?: string | undefined;
credentialStatus?: {
@@ -646,14 +646,21 @@ export declare const verifiablePresentationSchema: z.ZodObject<{
type: string;
} | undefined;
evidence?: {
type: EvidenceType;
result: EvidenceResult;
type: EvidenceType;
verifier?: string | undefined;
txn?: string | undefined;
timestamp?: string | undefined;
}[] | undefined;
}, {
type: string[];
proof: {
type: string;
created: string;
proofPurpose: string;
verificationMethod: string;
jws?: string | undefined;
};
issuer: string;
credentialSubject: {
id: string;
@@ -664,13 +671,6 @@ export declare const verifiablePresentationSchema: z.ZodObject<{
publicHandle?: string | undefined;
};
issuanceDate: string;
proof: {
type: string;
created: string;
proofPurpose: string;
verificationMethod: string;
jws?: string | undefined;
};
'@context': string[];
expirationDate?: string | undefined;
credentialStatus?: {
@@ -678,8 +678,8 @@ export declare const verifiablePresentationSchema: z.ZodObject<{
type: string;
} | undefined;
evidence?: {
type: EvidenceType;
result: EvidenceResult;
type: EvidenceType;
verifier?: string | undefined;
txn?: string | undefined;
timestamp?: string | undefined;
@@ -729,14 +729,14 @@ export declare const verifiablePresentationSchema: z.ZodObject<{
result: z.ZodNativeEnum<typeof EvidenceResult>;
timestamp: z.ZodOptional<z.ZodString>;
}, "strip", z.ZodTypeAny, {
type: EvidenceType;
result: EvidenceResult;
type: EvidenceType;
verifier?: string | undefined;
txn?: string | undefined;
timestamp?: string | undefined;
}, {
type: EvidenceType;
result: EvidenceResult;
type: EvidenceType;
verifier?: string | undefined;
txn?: string | undefined;
timestamp?: string | undefined;
@@ -762,6 +762,13 @@ export declare const verifiablePresentationSchema: z.ZodObject<{
}>;
}, "strip", z.ZodTypeAny, {
type: string[];
proof: {
type: string;
created: string;
proofPurpose: string;
verificationMethod: string;
jws?: string | undefined;
};
issuer: string;
credentialSubject: {
id: string;
@@ -772,13 +779,6 @@ export declare const verifiablePresentationSchema: z.ZodObject<{
sponsoringMember?: string | undefined;
};
issuanceDate: string;
proof: {
type: string;
created: string;
proofPurpose: string;
verificationMethod: string;
jws?: string | undefined;
};
'@context': string[];
expirationDate?: string | undefined;
credentialStatus?: {
@@ -786,14 +786,21 @@ export declare const verifiablePresentationSchema: z.ZodObject<{
type: string;
} | undefined;
evidence?: {
type: EvidenceType;
result: EvidenceResult;
type: EvidenceType;
verifier?: string | undefined;
txn?: string | undefined;
timestamp?: string | undefined;
}[] | undefined;
}, {
type: string[];
proof: {
type: string;
created: string;
proofPurpose: string;
verificationMethod: string;
jws?: string | undefined;
};
issuer: string;
credentialSubject: {
id: string;
@@ -804,13 +811,6 @@ export declare const verifiablePresentationSchema: z.ZodObject<{
sponsoringMember?: string | undefined;
};
issuanceDate: string;
proof: {
type: string;
created: string;
proofPurpose: string;
verificationMethod: string;
jws?: string | undefined;
};
'@context': string[];
expirationDate?: string | undefined;
credentialStatus?: {
@@ -818,8 +818,8 @@ export declare const verifiablePresentationSchema: z.ZodObject<{
type: string;
} | undefined;
evidence?: {
type: EvidenceType;
result: EvidenceResult;
type: EvidenceType;
verifier?: string | undefined;
txn?: string | undefined;
timestamp?: string | undefined;
@@ -849,19 +849,159 @@ export declare const verifiablePresentationSchema: z.ZodObject<{
challenge?: string | undefined;
}>;
}, "strip", z.ZodTypeAny, {
[x: string]: any;
'@context'?: unknown;
type?: unknown;
verifiableCredential?: unknown;
holder?: unknown;
proof?: unknown;
type: string[];
proof: {
type: string;
created: string;
proofPurpose: string;
verificationMethod: string;
jws?: string | undefined;
challenge?: string | undefined;
};
'@context': string[];
verifiableCredential: ({
type: string[];
proof: {
type: string;
created: string;
proofPurpose: string;
verificationMethod: string;
jws?: string | undefined;
};
issuer: string;
credentialSubject: {
id: string;
legalName: string;
assuranceLevel: LevelOfAssurance.LOA1 | LevelOfAssurance.LOA2;
residentNumber: string;
issueJurisdiction: "DSB";
publicHandle?: string | undefined;
};
issuanceDate: string;
'@context': string[];
expirationDate?: string | undefined;
credentialStatus?: {
id: string;
type: string;
} | undefined;
evidence?: {
result: EvidenceResult;
type: EvidenceType;
verifier?: string | undefined;
txn?: string | undefined;
timestamp?: string | undefined;
}[] | undefined;
} | {
type: string[];
proof: {
type: string;
created: string;
proofPurpose: string;
verificationMethod: string;
jws?: string | undefined;
};
issuer: string;
credentialSubject: {
id: string;
assuranceLevel: LevelOfAssurance.LOA2 | LevelOfAssurance.LOA3;
citizenNumber: string;
oathDate: string;
governanceRights?: string[] | undefined;
sponsoringMember?: string | undefined;
};
issuanceDate: string;
'@context': string[];
expirationDate?: string | undefined;
credentialStatus?: {
id: string;
type: string;
} | undefined;
evidence?: {
result: EvidenceResult;
type: EvidenceType;
verifier?: string | undefined;
txn?: string | undefined;
timestamp?: string | undefined;
}[] | undefined;
})[];
holder: string;
}, {
[x: string]: any;
'@context'?: unknown;
type?: unknown;
verifiableCredential?: unknown;
holder?: unknown;
proof?: unknown;
type: string[];
proof: {
type: string;
created: string;
proofPurpose: string;
verificationMethod: string;
jws?: string | undefined;
challenge?: string | undefined;
};
'@context': string[];
verifiableCredential: ({
type: string[];
proof: {
type: string;
created: string;
proofPurpose: string;
verificationMethod: string;
jws?: string | undefined;
};
issuer: string;
credentialSubject: {
id: string;
legalName: string;
assuranceLevel: LevelOfAssurance.LOA1 | LevelOfAssurance.LOA2;
residentNumber: string;
issueJurisdiction: "DSB";
publicHandle?: string | undefined;
};
issuanceDate: string;
'@context': string[];
expirationDate?: string | undefined;
credentialStatus?: {
id: string;
type: string;
} | undefined;
evidence?: {
result: EvidenceResult;
type: EvidenceType;
verifier?: string | undefined;
txn?: string | undefined;
timestamp?: string | undefined;
}[] | undefined;
} | {
type: string[];
proof: {
type: string;
created: string;
proofPurpose: string;
verificationMethod: string;
jws?: string | undefined;
};
issuer: string;
credentialSubject: {
id: string;
assuranceLevel: LevelOfAssurance.LOA2 | LevelOfAssurance.LOA3;
citizenNumber: string;
oathDate: string;
governanceRights?: string[] | undefined;
sponsoringMember?: string | undefined;
};
issuanceDate: string;
'@context': string[];
expirationDate?: string | undefined;
credentialStatus?: {
id: string;
type: string;
} | undefined;
evidence?: {
result: EvidenceResult;
type: EvidenceType;
verifier?: string | undefined;
txn?: string | undefined;
timestamp?: string | undefined;
}[] | undefined;
})[];
holder: string;
}>;
export type VerifiablePresentation = z.infer<typeof verifiablePresentationSchema>;
/**
@@ -896,18 +1036,19 @@ export declare const eResidencyApplicationSchema: z.ZodObject<{
postalCode: z.ZodOptional<z.ZodString>;
country: z.ZodOptional<z.ZodString>;
}, "strip", z.ZodTypeAny, {
region?: string | undefined;
street?: string | undefined;
city?: string | undefined;
region?: string | undefined;
postalCode?: string | undefined;
country?: string | undefined;
}, {
region?: string | undefined;
street?: string | undefined;
city?: string | undefined;
region?: string | undefined;
postalCode?: string | undefined;
country?: string | undefined;
}>>;
deviceFingerprint: z.ZodOptional<z.ZodString>;
identityDocument: z.ZodOptional<z.ZodObject<{
type: z.ZodEnum<["passport", "national_id", "drivers_license"]>;
number: z.ZodString;
@@ -948,20 +1089,24 @@ export declare const eResidencyApplicationSchema: z.ZodObject<{
kycStatus: z.ZodOptional<z.ZodEnum<["pending", "passed", "failed", "requires_edd"]>>;
sanctionsStatus: z.ZodOptional<z.ZodEnum<["pending", "clear", "flag"]>>;
pepStatus: z.ZodOptional<z.ZodEnum<["pending", "clear", "flag"]>>;
riskScore: z.ZodOptional<z.ZodNumber>;
kycResults: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
sanctionsResults: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
riskAssessment: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
createdAt: z.ZodString;
updatedAt: z.ZodString;
}, "strip", z.ZodTypeAny, {
id: string;
status: ApplicationStatus;
id: string;
email: string;
createdAt: string;
updatedAt: string;
givenName: string;
familyName: string;
address?: {
region?: string | undefined;
street?: string | undefined;
city?: string | undefined;
region?: string | undefined;
postalCode?: string | undefined;
country?: string | undefined;
} | undefined;
@@ -969,6 +1114,7 @@ export declare const eResidencyApplicationSchema: z.ZodObject<{
dateOfBirth?: string | undefined;
nationality?: string | undefined;
phone?: string | undefined;
deviceFingerprint?: string | undefined;
identityDocument?: {
number: string;
type: "passport" | "national_id" | "drivers_license";
@@ -985,21 +1131,25 @@ export declare const eResidencyApplicationSchema: z.ZodObject<{
reviewedAt?: string | undefined;
reviewedBy?: string | undefined;
rejectionReason?: string | undefined;
kycStatus?: "pending" | "failed" | "passed" | "requires_edd" | undefined;
kycStatus?: "failed" | "pending" | "passed" | "requires_edd" | undefined;
sanctionsStatus?: "pending" | "clear" | "flag" | undefined;
pepStatus?: "pending" | "clear" | "flag" | undefined;
riskScore?: number | undefined;
kycResults?: Record<string, unknown> | undefined;
sanctionsResults?: Record<string, unknown> | undefined;
riskAssessment?: Record<string, unknown> | undefined;
}, {
id: string;
status: ApplicationStatus;
id: string;
email: string;
createdAt: string;
updatedAt: string;
givenName: string;
familyName: string;
address?: {
region?: string | undefined;
street?: string | undefined;
city?: string | undefined;
region?: string | undefined;
postalCode?: string | undefined;
country?: string | undefined;
} | undefined;
@@ -1007,6 +1157,7 @@ export declare const eResidencyApplicationSchema: z.ZodObject<{
dateOfBirth?: string | undefined;
nationality?: string | undefined;
phone?: string | undefined;
deviceFingerprint?: string | undefined;
identityDocument?: {
number: string;
type: "passport" | "national_id" | "drivers_license";
@@ -1023,9 +1174,13 @@ export declare const eResidencyApplicationSchema: z.ZodObject<{
reviewedAt?: string | undefined;
reviewedBy?: string | undefined;
rejectionReason?: string | undefined;
kycStatus?: "pending" | "failed" | "passed" | "requires_edd" | undefined;
kycStatus?: "failed" | "pending" | "passed" | "requires_edd" | undefined;
sanctionsStatus?: "pending" | "clear" | "flag" | undefined;
pepStatus?: "pending" | "clear" | "flag" | undefined;
riskScore?: number | undefined;
kycResults?: Record<string, unknown> | undefined;
sanctionsResults?: Record<string, unknown> | undefined;
riskAssessment?: Record<string, unknown> | undefined;
}>;
export type eResidencyApplication = z.infer<typeof eResidencyApplicationSchema>;
/**
@@ -1100,8 +1255,8 @@ export declare const eCitizenshipApplicationSchema: z.ZodObject<{
createdAt: z.ZodString;
updatedAt: z.ZodString;
}, "strip", z.ZodTypeAny, {
id: string;
status: ApplicationStatus;
id: string;
createdAt: string;
updatedAt: string;
applicantDid: string;
@@ -1134,8 +1289,8 @@ export declare const eCitizenshipApplicationSchema: z.ZodObject<{
oathVersion?: string | undefined;
} | undefined;
}, {
id: string;
status: ApplicationStatus;
id: string;
createdAt: string;
updatedAt: string;
applicantDid: string;

View File

@@ -1 +1 @@
{"version":3,"file":"eresidency.d.ts","sourceRoot":"","sources":["eresidency.ts"],"names":[],"mappings":"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"}
{"version":3,"file":"eresidency.d.ts","sourceRoot":"","sources":["eresidency.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB;;GAEG;AACH,oBAAY,gBAAgB;IAC1B,IAAI,SAAS,CAAE,8BAA8B;IAC7C,IAAI,SAAS,CAAE,qDAAqD;IACpE,IAAI,SAAS;CACd;AAED;;GAEG;AACH,oBAAY,eAAe;IACzB,QAAQ,aAAa;IACrB,OAAO,YAAY;IACnB,QAAQ,aAAa;IACrB,OAAO,YAAY;CACpB;AAED;;GAEG;AACH,oBAAY,YAAY;IACtB,oBAAoB,yBAAyB;IAC7C,aAAa,kBAAkB;IAC/B,eAAe,oBAAoB;IACnC,cAAc,mBAAmB;IACjC,WAAW,gBAAgB;IAC3B,eAAe,oBAAoB;IACnC,qBAAqB,0BAA0B;CAChD;AAED;;GAEG;AACH,oBAAY,cAAc;IACxB,IAAI,SAAS;IACb,IAAI,SAAS;IACb,MAAM,WAAW;CAClB;AAED;;;GAGG;AACH,eAAO,MAAM,gCAAgC;;;;;;;;;;;;;;;;;;;;;EAO3C,CAAC;AAEH,MAAM,MAAM,0BAA0B,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,gCAAgC,CAAC,CAAC;AAE1F;;;GAGG;AACH,eAAO,MAAM,+BAA+B;;;;;;;;;;;;;;;;;;;;;EAO1C,CAAC;AAEH,MAAM,MAAM,yBAAyB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,+BAA+B,CAAC,CAAC;AAExF;;GAEG;AACH,eAAO,MAAM,cAAc;;;;;;;;;;;;;;;;;;EAMzB,CAAC;AAEH,MAAM,MAAM,QAAQ,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,cAAc,CAAC,CAAC;AAEtD;;GAEG;AACH,eAAO,MAAM,yCAAyC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAYpD,CAAC;AAEH,MAAM,MAAM,mCAAmC,GAAG,CAAC,CAAC,KAAK,CACvD,OAAO,yCAAyC,CACjD,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,mCAAmC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAe9C,CAAC;AAEH,MAAM,MAAM,6BAA6B,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,mCAAmC,CAAC,CAAC;AAEhG;;GAEG;AACH,eAAO,MAAM,wCAAwC;;;;;;;;;;;;;;;;;;;;;;;;EAQnD,CAAC;AAEH,MAAM,MAAM,kCAAkC,GAAG,CAAC,CAAC,KAAK,CACtD,OAAO,wCAAwC,CAChD,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,yBAAyB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAuBpC,CAAC;AAEH,MAAM,MAAM,mBAAmB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,yBAAyB,CAAC,CAAC;AAE5E;;;GAGG;AACH,eAAO,MAAM,wBAAwB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAuBnC,CAAC;AAEH,MAAM,MAAM,kBAAkB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,wBAAwB,CAAC,CAAC;AAE1E;;GAEG;AACH,eAAO,MAAM,4BAA4B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAevC,CAAC;AAEH,MAAM,MAAM,sBAAsB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,4BAA4B,CAAC,CAAC;AAElF;;GAEG;AACH,oBAAY,iBAAiB;IAC3B,KAAK,UAAU;IACf,SAAS,cAAc;IACvB,YAAY,iBAAiB;IAC7B,WAAW,gBAAgB;IAC3B,QAAQ,aAAa;IACrB,QAAQ,aAAa;IACrB,QAAQ,aAAa;IACrB,SAAS,cAAc;CACxB;AAED;;GAEG;AACH,eAAO,MAAM,2BAA2B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAiDtC,CAAC;AAEH,MAAM,MAAM,qBAAqB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,2BAA2B,CAAC,CAAC;AAEhF;;GAEG;AACH,eAAO,MAAM,6BAA6B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA4CxC,CAAC;AAEH,MAAM,MAAM,uBAAuB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,6BAA6B,CAAC,CAAC"}

View File

@@ -185,8 +185,10 @@ export const eCitizenCredentialSchema = z.object({
*/
export const verifiablePresentationSchema = z.object({
'@context': z.array(z.string()).min(1),
type: z.array(z.string()).includes('VerifiablePresentation'),
verifiableCredential: z.array(z.union([eResidentCredentialSchema, eCitizenCredentialSchema])),
type: z.array(z.string()).refine((arr) => arr.includes('VerifiablePresentation'), {
message: 'Type must include VerifiablePresentation',
}),
verifiableCredential: z.array(z.union([eResidentCredentialSchema, eCitizenCredentialSchema])).min(1),
holder: z.string().describe('DID of the holder'),
proof: z.object({
type: z.string(),
@@ -232,6 +234,7 @@ export const eResidencyApplicationSchema = z.object({
country: z.string().optional(),
})
.optional(),
deviceFingerprint: z.string().optional(),
identityDocument: z
.object({
type: z.enum(['passport', 'national_id', 'drivers_license']),
@@ -256,6 +259,10 @@ export const eResidencyApplicationSchema = z.object({
kycStatus: z.enum(['pending', 'passed', 'failed', 'requires_edd']).optional(),
sanctionsStatus: z.enum(['pending', 'clear', 'flag']).optional(),
pepStatus: z.enum(['pending', 'clear', 'flag']).optional(),
riskScore: z.number().min(0).max(1).optional(),
kycResults: z.record(z.unknown()).optional(),
sanctionsResults: z.record(z.unknown()).optional(),
riskAssessment: z.record(z.unknown()).optional(),
createdAt: z.string(),
updatedAt: z.string(),
});

File diff suppressed because one or more lines are too long

View File

@@ -12,18 +12,18 @@ export declare const LedgerEntrySchema: z.ZodObject<{
}, "strip", z.ZodTypeAny, {
id: string;
type: "debit" | "credit";
createdAt: string | Date;
amount: number;
currency: string;
createdAt: string | Date;
accountId: string;
description?: string | undefined;
reference?: string | undefined;
}, {
id: string;
type: "debit" | "credit";
createdAt: string | Date;
amount: number;
currency: string;
createdAt: string | Date;
accountId: string;
description?: string | undefined;
reference?: string | undefined;

View File

@@ -10,21 +10,21 @@ export declare const PaymentSchema: z.ZodObject<{
createdAt: z.ZodUnion<[z.ZodDate, z.ZodString]>;
updatedAt: z.ZodUnion<[z.ZodDate, z.ZodString]>;
}, "strip", z.ZodTypeAny, {
status: "failed" | "completed" | "pending" | "processing" | "refunded";
id: string;
status: "pending" | "processing" | "completed" | "failed" | "refunded";
createdAt: string | Date;
updatedAt: string | Date;
amount: number;
currency: string;
createdAt: string | Date;
updatedAt: string | Date;
paymentMethod: string;
transactionId?: string | undefined;
}, {
status: "failed" | "completed" | "pending" | "processing" | "refunded";
id: string;
status: "pending" | "processing" | "completed" | "failed" | "refunded";
createdAt: string | Date;
updatedAt: string | Date;
amount: number;
currency: string;
createdAt: string | Date;
updatedAt: string | Date;
paymentMethod: string;
transactionId?: string | undefined;
}>;
@@ -38,7 +38,7 @@ export declare const CreatePaymentSchema: z.ZodObject<Omit<{
transactionId: z.ZodOptional<z.ZodString>;
createdAt: z.ZodUnion<[z.ZodDate, z.ZodString]>;
updatedAt: z.ZodUnion<[z.ZodDate, z.ZodString]>;
}, "id" | "status" | "createdAt" | "updatedAt" | "transactionId">, "strip", z.ZodTypeAny, {
}, "status" | "id" | "createdAt" | "updatedAt" | "transactionId">, "strip", z.ZodTypeAny, {
amount: number;
currency: string;
paymentMethod: string;

View File

@@ -6,14 +6,14 @@ export declare const UserSchema: z.ZodObject<{
createdAt: z.ZodUnion<[z.ZodDate, z.ZodString]>;
updatedAt: z.ZodUnion<[z.ZodDate, z.ZodString]>;
}, "strip", z.ZodTypeAny, {
id: string;
name: string;
id: string;
email: string;
createdAt: string | Date;
updatedAt: string | Date;
}, {
id: string;
name: string;
id: string;
email: string;
createdAt: string | Date;
updatedAt: string | Date;

View File

@@ -33,7 +33,6 @@ export declare const VCSchema: z.ZodObject<{
subject: string;
credentialSubject: Record<string, unknown>;
issuanceDate: string;
expirationDate?: string | undefined;
proof?: {
type: string;
created: string;
@@ -41,6 +40,7 @@ export declare const VCSchema: z.ZodObject<{
verificationMethod: string;
jws: string;
} | undefined;
expirationDate?: string | undefined;
}, {
id: string;
type: string[];
@@ -48,7 +48,6 @@ export declare const VCSchema: z.ZodObject<{
subject: string;
credentialSubject: Record<string, unknown>;
issuanceDate: string;
expirationDate?: string | undefined;
proof?: {
type: string;
created: string;
@@ -56,6 +55,7 @@ export declare const VCSchema: z.ZodObject<{
verificationMethod: string;
jws: string;
} | undefined;
expirationDate?: string | undefined;
}>;
export type VC = z.infer<typeof VCSchema>;
export declare const IssueVCSchema: z.ZodObject<{
@@ -107,7 +107,6 @@ export declare const VerifyVCSchema: z.ZodObject<{
subject: string;
credentialSubject: Record<string, unknown>;
issuanceDate: string;
expirationDate?: string | undefined;
proof?: {
type: string;
created: string;
@@ -115,6 +114,7 @@ export declare const VerifyVCSchema: z.ZodObject<{
verificationMethod: string;
jws: string;
} | undefined;
expirationDate?: string | undefined;
}, {
id: string;
type: string[];
@@ -122,7 +122,6 @@ export declare const VerifyVCSchema: z.ZodObject<{
subject: string;
credentialSubject: Record<string, unknown>;
issuanceDate: string;
expirationDate?: string | undefined;
proof?: {
type: string;
created: string;
@@ -130,6 +129,7 @@ export declare const VerifyVCSchema: z.ZodObject<{
verificationMethod: string;
jws: string;
} | undefined;
expirationDate?: string | undefined;
}>;
}, "strip", z.ZodTypeAny, {
credential: {
@@ -139,7 +139,6 @@ export declare const VerifyVCSchema: z.ZodObject<{
subject: string;
credentialSubject: Record<string, unknown>;
issuanceDate: string;
expirationDate?: string | undefined;
proof?: {
type: string;
created: string;
@@ -147,6 +146,7 @@ export declare const VerifyVCSchema: z.ZodObject<{
verificationMethod: string;
jws: string;
} | undefined;
expirationDate?: string | undefined;
};
}, {
credential: {
@@ -156,7 +156,6 @@ export declare const VerifyVCSchema: z.ZodObject<{
subject: string;
credentialSubject: Record<string, unknown>;
issuanceDate: string;
expirationDate?: string | undefined;
proof?: {
type: string;
created: string;
@@ -164,6 +163,7 @@ export declare const VerifyVCSchema: z.ZodObject<{
verificationMethod: string;
jws: string;
} | undefined;
expirationDate?: string | undefined;
};
}>;
export type VerifyVC = z.infer<typeof VerifyVCSchema>;

View File

@@ -49,6 +49,16 @@ const envSchema = z.object({
ENTRA_CLIENT_ID: z.string().optional(),
ENTRA_CLIENT_SECRET: z.string().optional(),
ENTRA_CREDENTIAL_MANIFEST_ID: z.string().optional(),
ENTRA_MANIFESTS: z.string().optional(), // JSON object mapping manifest names to IDs
// Entra Rate Limiting
ENTRA_RATE_LIMIT_ISSUANCE: z.string().optional(),
ENTRA_RATE_LIMIT_VERIFICATION: z.string().optional(),
ENTRA_RATE_LIMIT_STATUS_CHECK: z.string().optional(),
ENTRA_RATE_LIMIT_GLOBAL: z.string().optional(),
// Credential Display/Images
ENTRA_CREDENTIAL_LOGO_URI: z.string().url().optional(),
ENTRA_CREDENTIAL_BG_COLOR: z.string().optional(),
ENTRA_CREDENTIAL_TEXT_COLOR: z.string().optional(),
// Credential Rate Limiting
CREDENTIAL_RATE_LIMIT_PER_USER: z.string().optional(),

View File

@@ -10,6 +10,7 @@ export * from './middleware';
export * from './validation';
export * from './auth';
export * from './rate-limit-credential';
export * from './rate-limit-entra';
export * from './authorization';
export * from './compliance';
export * from './retry';

View File

@@ -0,0 +1,144 @@
/**
* Entra VerifiedID API rate limiting
* Specific rate limits for Entra VerifiedID endpoints to prevent API quota exhaustion
*/
import { FastifyInstance, FastifyRequest } from 'fastify';
import fastifyRateLimit from '@fastify/rate-limit';
import { getEnv } from './env';
export interface EntraRateLimitConfig {
issuance?: {
max: number;
timeWindow: string | number;
};
verification?: {
max: number;
timeWindow: string | number;
};
statusCheck?: {
max: number;
timeWindow: string | number;
};
global?: {
max: number;
timeWindow: string | number;
};
}
/**
* Register Entra VerifiedID-specific rate limiting
*/
export async function registerEntraRateLimit(
server: FastifyInstance,
config?: EntraRateLimitConfig
): Promise<void> {
const env = getEnv();
// Default configuration - conservative limits to avoid API quota issues
const defaultConfig: Required<EntraRateLimitConfig> = {
issuance: {
max: parseInt(env.ENTRA_RATE_LIMIT_ISSUANCE || '10', 10),
timeWindow: '1 minute',
},
verification: {
max: parseInt(env.ENTRA_RATE_LIMIT_VERIFICATION || '20', 10),
timeWindow: '1 minute',
},
statusCheck: {
max: parseInt(env.ENTRA_RATE_LIMIT_STATUS_CHECK || '30', 10),
timeWindow: '1 minute',
},
global: {
max: parseInt(env.ENTRA_RATE_LIMIT_GLOBAL || '50', 10),
timeWindow: '1 minute',
},
};
const finalConfig = { ...defaultConfig, ...config };
// Global Entra API rate limit
await server.register(fastifyRateLimit, {
max: finalConfig.global.max,
timeWindow: finalConfig.global.timeWindow,
keyGenerator: (request: FastifyRequest) => {
// Rate limit by IP for Entra endpoints
return `entra:global:${request.ip}`;
},
errorResponseBuilder: (_request, context) => {
return {
error: {
code: 'ENTRA_RATE_LIMIT_EXCEEDED',
message: `Entra API rate limit exceeded, retry in ${Math.ceil(context.ttl / 1000)} seconds`,
},
};
},
skipOnError: false,
});
// Issuance-specific rate limit
await server.register(fastifyRateLimit, {
max: finalConfig.issuance.max,
timeWindow: finalConfig.issuance.timeWindow,
keyGenerator: (request: FastifyRequest) => {
const userId = (request as any).user?.id || 'anonymous';
return `entra:issuance:${userId}:${request.ip}`;
},
errorResponseBuilder: (_request, context) => {
return {
error: {
code: 'ENTRA_ISSUANCE_RATE_LIMIT_EXCEEDED',
message: `Entra issuance rate limit exceeded, retry in ${Math.ceil(context.ttl / 1000)} seconds`,
},
};
},
skipOnError: false,
});
// Verification-specific rate limit
await server.register(fastifyRateLimit, {
max: finalConfig.verification.max,
timeWindow: finalConfig.verification.timeWindow,
keyGenerator: (request: FastifyRequest) => {
return `entra:verification:${request.ip}`;
},
errorResponseBuilder: (_request, context) => {
return {
error: {
code: 'ENTRA_VERIFICATION_RATE_LIMIT_EXCEEDED',
message: `Entra verification rate limit exceeded, retry in ${Math.ceil(context.ttl / 1000)} seconds`,
},
};
},
skipOnError: false,
});
// Status check-specific rate limit
await server.register(fastifyRateLimit, {
max: finalConfig.statusCheck.max,
timeWindow: finalConfig.statusCheck.timeWindow,
keyGenerator: (request: FastifyRequest) => {
const requestId = (request.params as any)?.requestId || (request.query as any)?.requestId || 'unknown';
return `entra:status:${requestId}`;
},
errorResponseBuilder: (_request, context) => {
return {
error: {
code: 'ENTRA_STATUS_CHECK_RATE_LIMIT_EXCEEDED',
message: `Entra status check rate limit exceeded, retry in ${Math.ceil(context.ttl / 1000)} seconds`,
},
};
},
skipOnError: false,
});
}
/**
* Create Entra rate limit plugin
*/
export function createEntraRateLimitPlugin(config?: EntraRateLimitConfig) {
return async function (server: FastifyInstance) {
await registerEntraRateLimit(server, config);
};
}

View File

@@ -1 +1 @@
{"version":3,"file":"storage.d.ts","sourceRoot":"","sources":["storage.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EACL,QAAQ,EAKT,MAAM,oBAAoB,CAAC;AAG5B,MAAM,WAAW,aAAa;IAC5B,QAAQ,EAAE,IAAI,GAAG,KAAK,CAAC;IACvB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED,MAAM,WAAW,aAAa;IAC5B,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,EAAE,MAAM,GAAG,MAAM,CAAC;IACzB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACnC;AAED,qBAAa,aAAa;IAIZ,SAAS,CAAC,MAAM,EAAE,aAAa;IAH3C,SAAS,CAAC,QAAQ,EAAE,QAAQ,CAAC;IAC7B,SAAS,CAAC,MAAM,EAAE,MAAM,CAAC;gBAEH,MAAM,EAAE,aAAa;IAcrC,MAAM,CAAC,MAAM,EAAE,aAAa,GAAG,OAAO,CAAC,MAAM,CAAC;IAa9C,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAkBtC,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IASlC,eAAe,CAAC,GAAG,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAShE,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;CAelD"}
{"version":3,"file":"storage.d.ts","sourceRoot":"","sources":["storage.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EACL,QAAQ,EAKT,MAAM,oBAAoB,CAAC;AAG5B,MAAM,WAAW,aAAa;IAC5B,QAAQ,EAAE,IAAI,GAAG,KAAK,CAAC;IACvB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED,MAAM,WAAW,aAAa;IAC5B,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,EAAE,MAAM,GAAG,MAAM,CAAC;IACzB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACnC;AAED,qBAAa,aAAa;IAIZ,SAAS,CAAC,MAAM,EAAE,aAAa;IAH3C,SAAS,CAAC,QAAQ,EAAE,QAAQ,CAAC;IAC7B,SAAS,CAAC,MAAM,EAAE,MAAM,CAAC;gBAEH,MAAM,EAAE,aAAa;IAcrC,MAAM,CAAC,MAAM,EAAE,aAAa,GAAG,OAAO,CAAC,MAAM,CAAC;IAa9C,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAqBtC,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IASlC,eAAe,CAAC,GAAG,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAShE,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;CAelD"}

View File

@@ -41,8 +41,11 @@ export class StorageClient {
throw new Error(`Object ${key} not found or empty`);
}
const chunks = [];
for await (const chunk of response.Body) {
chunks.push(chunk);
if (response.Body) {
const body = response.Body;
for await (const chunk of body) {
chunks.push(chunk);
}
}
return Buffer.concat(chunks);
}

View File

@@ -1 +1 @@
{"version":3,"file":"storage.js","sourceRoot":"","sources":["storage.ts"],"names":[],"mappings":"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"}
{"version":3,"file":"storage.js","sourceRoot":"","sources":["storage.ts"],"names":[],"mappings":"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"}

View File

@@ -69,8 +69,11 @@ export class StorageClient {
}
const chunks: Uint8Array[] = [];
for await (const chunk of response.Body as any) {
chunks.push(chunk);
if (response.Body) {
const body = response.Body as AsyncIterable<Uint8Array>;
for await (const chunk of body) {
chunks.push(chunk);
}
}
return Buffer.concat(chunks);
}

View File

@@ -9,7 +9,7 @@ export class WORMStorage extends StorageClient {
if (exists) {
throw new Error(`Object ${object.key} already exists in WORM storage`);
}
return super.upload(object);
return await super.upload(object);
}
async delete(_key) {
throw new Error('Deletion not allowed in WORM mode');

View File

@@ -1 +1 @@
{"version":3,"file":"worm.js","sourceRoot":"","sources":["worm.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,aAAa,EAAiB,MAAM,WAAW,CAAC;AAEzD,MAAM,OAAO,WAAY,SAAQ,aAAa;IAC5C,KAAK,CAAC,MAAM,CAAC,MAAqB;QAChC,gCAAgC;QAChC,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,YAAY,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QACnD,IAAI,MAAM,EAAE,CAAC;YACX,MAAM,IAAI,KAAK,CAAC,UAAU,MAAM,CAAC,GAAG,iCAAiC,CAAC,CAAC;QACzE,CAAC;QACD,OAAO,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;IAC9B,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,IAAY;QACvB,MAAM,IAAI,KAAK,CAAC,mCAAmC,CAAC,CAAC;IACvD,CAAC;CACF"}
{"version":3,"file":"worm.js","sourceRoot":"","sources":["worm.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,aAAa,EAAiB,MAAM,WAAW,CAAC;AAEzD,MAAM,OAAO,WAAY,SAAQ,aAAa;IAC5C,KAAK,CAAC,MAAM,CAAC,MAAqB;QAChC,gCAAgC;QAChC,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,YAAY,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QACnD,IAAI,MAAM,EAAE,CAAC;YACX,MAAM,IAAI,KAAK,CAAC,UAAU,MAAM,CAAC,GAAG,iCAAiC,CAAC,CAAC;QACzE,CAAC;QACD,OAAO,MAAM,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;IACpC,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,IAAY;QACvB,MAAM,IAAI,KAAK,CAAC,mCAAmC,CAAC,CAAC;IACvD,CAAC;CACF"}

View File

@@ -11,7 +11,7 @@ export class WORMStorage extends StorageClient {
if (exists) {
throw new Error(`Object ${object.key} already exists in WORM storage`);
}
return super.upload(object);
return await super.upload(object);
}
async delete(_key: string): Promise<void> {

View File

@@ -25,7 +25,7 @@ export interface BadgeProps
extends React.HTMLAttributes<HTMLDivElement>,
VariantProps<typeof badgeVariants> {}
export function Badge({ className, variant, ...props }: BadgeProps) {
export function Badge({ className, variant, ...props }: BadgeProps): JSX.Element {
return <div className={cn(badgeVariants({ variant }), className)} {...props} />;
}

View File

@@ -1,5 +1,3 @@
import React from 'react';
import Link from 'next/link';
import { cn } from '../lib/utils';
export interface BreadcrumbItem {
@@ -10,9 +8,10 @@ export interface BreadcrumbItem {
export interface BreadcrumbsProps {
items: BreadcrumbItem[];
className?: string;
LinkComponent?: React.ComponentType<{ href: string; className?: string; children: React.ReactNode }>;
}
export function Breadcrumbs({ items, className }: BreadcrumbsProps) {
export function Breadcrumbs({ items, className, LinkComponent }: BreadcrumbsProps): JSX.Element {
return (
<nav aria-label="Breadcrumb" className={cn('flex', className)}>
<ol className="flex items-center space-x-2 text-sm">
@@ -26,9 +25,15 @@ export function Breadcrumbs({ items, className }: BreadcrumbsProps) {
{item.label}
</span>
) : item.href ? (
<Link href={item.href} className="text-gray-600 hover:text-gray-900">
{item.label}
</Link>
LinkComponent ? (
<LinkComponent href={item.href} className="text-gray-600 hover:text-gray-900">
{item.label}
</LinkComponent>
) : (
<a href={item.href} className="text-gray-600 hover:text-gray-900">
{item.label}
</a>
)
) : (
<span className="text-gray-600">{item.label}</span>
)}

View File

@@ -32,7 +32,7 @@ export interface ButtonProps
export const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
({ className, variant, size, ...props }, ref) => {
return (
<button className={cn(buttonVariants({ variant, size, className }))} ref={ref} {...props} />
<button className={cn(buttonVariants({ variant, size }), className)} ref={ref} {...props} />
);
}
);

View File

@@ -16,27 +16,29 @@ export interface DropdownProps {
className?: string;
}
export function Dropdown({ trigger, items, align = 'left', className }: DropdownProps) {
export function Dropdown({ trigger, items, align = 'left', className }: DropdownProps): JSX.Element {
const [isOpen, setIsOpen] = useState(false);
const dropdownRef = useRef<HTMLDivElement>(null);
useEffect(() => {
const handleClickOutside = (event: MouseEvent) => {
if (dropdownRef.current && !dropdownRef.current.contains(event.target as Node)) {
const handleClickOutside = (event: MouseEvent): void => {
if (dropdownRef.current && event.target instanceof Node && !dropdownRef.current.contains(event.target)) {
setIsOpen(false);
}
};
if (isOpen) {
if (isOpen && typeof document !== 'undefined') {
document.addEventListener('mousedown', handleClickOutside);
}
return () => {
document.removeEventListener('mousedown', handleClickOutside);
if (typeof document !== 'undefined') {
document.removeEventListener('mousedown', handleClickOutside);
}
};
}, [isOpen]);
const handleItemClick = (item: DropdownItem) => {
const handleItemClick = (item: DropdownItem): void => {
if (item.disabled) return;
item.onClick?.();
setIsOpen(false);

View File

@@ -1,7 +1,7 @@
import React from 'react';
import { cn } from '../lib/utils';
export interface InputProps extends React.InputHTMLAttributes<HTMLInputElement> {}
export type InputProps = React.InputHTMLAttributes<HTMLInputElement>;
export const Input = React.forwardRef<HTMLInputElement, InputProps>(
({ className, type, ...props }, ref) => {

View File

@@ -1,7 +1,7 @@
import React from 'react';
import { cn } from '../lib/utils';
export interface LabelProps extends React.LabelHTMLAttributes<HTMLLabelElement> {}
export type LabelProps = React.LabelHTMLAttributes<HTMLLabelElement>;
export const Label = React.forwardRef<HTMLLabelElement, LabelProps>(
({ className, ...props }, ref) => {

View File

@@ -20,15 +20,17 @@ export function Modal({
children,
size = 'md',
showCloseButton = true,
}: ModalProps) {
}: ModalProps): JSX.Element | null {
useEffect(() => {
if (open) {
if (open && typeof document !== 'undefined') {
document.body.style.overflow = 'hidden';
} else {
} else if (typeof document !== 'undefined') {
document.body.style.overflow = '';
}
return () => {
document.body.style.overflow = '';
if (typeof document !== 'undefined') {
document.body.style.overflow = '';
}
};
}, [open]);
@@ -102,8 +104,8 @@ export function ConfirmModal({
confirmText = 'Confirm',
cancelText = 'Cancel',
variant = 'default',
}: ConfirmModalProps) {
const handleConfirm = () => {
}: ConfirmModalProps): JSX.Element {
const handleConfirm = (): void => {
onConfirm();
onClose();
};

View File

@@ -1,7 +1,7 @@
import React from 'react';
import { cn } from '../lib/utils';
export interface SelectProps extends React.SelectHTMLAttributes<HTMLSelectElement> {}
export type SelectProps = React.SelectHTMLAttributes<HTMLSelectElement>;
export const Select = React.forwardRef<HTMLSelectElement, SelectProps>(
({ className, children, ...props }, ref) => {

View File

@@ -1,9 +1,9 @@
import React from 'react';
import { cn } from '../lib/utils';
export interface SkeletonProps extends React.HTMLAttributes<HTMLDivElement> {}
export type SkeletonProps = React.HTMLAttributes<HTMLDivElement>;
export function Skeleton({ className, ...props }: SkeletonProps) {
export function Skeleton({ className, ...props }: SkeletonProps): JSX.Element {
return <div className={cn('animate-pulse rounded-md bg-muted', className)} {...props} />;
}

View File

@@ -1,4 +1,4 @@
import React, { createContext, useContext, useState, ReactNode } from 'react';
import { createContext, useContext, useState, ReactNode } from 'react';
import { cn } from '../lib/utils';
interface TabsContextType {
@@ -16,12 +16,12 @@ export interface TabsProps {
className?: string;
}
export function Tabs({ defaultValue, value: controlledValue, onValueChange, children, className }: TabsProps) {
export function Tabs({ defaultValue, value: controlledValue, onValueChange, children, className }: TabsProps): JSX.Element {
const [internalValue, setInternalValue] = useState(defaultValue || '');
const isControlled = controlledValue !== undefined;
const currentValue = isControlled ? controlledValue : internalValue;
const handleValueChange = (newValue: string) => {
const handleValueChange = (newValue: string): void => {
if (!isControlled) {
setInternalValue(newValue);
}
@@ -40,7 +40,7 @@ export interface TabsListProps {
className?: string;
}
export function TabsList({ children, className }: TabsListProps) {
export function TabsList({ children, className }: TabsListProps): JSX.Element {
return (
<div
className={cn(
@@ -60,7 +60,7 @@ export interface TabsTriggerProps {
className?: string;
}
export function TabsTrigger({ value, children, className }: TabsTriggerProps) {
export function TabsTrigger({ value, children, className }: TabsTriggerProps): JSX.Element {
const context = useContext(TabsContext);
if (!context) {
throw new Error('TabsTrigger must be used within Tabs');
@@ -94,7 +94,7 @@ export interface TabsContentProps {
className?: string;
}
export function TabsContent({ value, children, className }: TabsContentProps) {
export function TabsContent({ value, children, className }: TabsContentProps): JSX.Element | null {
const context = useContext(TabsContext);
if (!context) {
throw new Error('TabsContent must be used within Tabs');

View File

@@ -1,7 +1,7 @@
import React from 'react';
import { cn } from '../lib/utils';
export interface TextareaProps extends React.TextareaHTMLAttributes<HTMLTextAreaElement> {}
export type TextareaProps = React.TextareaHTMLAttributes<HTMLTextAreaElement>;
export const Textarea = React.forwardRef<HTMLTextAreaElement, TextareaProps>(
({ className, ...props }, ref) => {

View File

@@ -1,5 +1,4 @@
import React, { createContext, useContext, useState, useCallback, ReactNode } from 'react';
import { cn } from '../lib/utils';
import { createContext, useContext, useState, useCallback, ReactNode } from 'react';
import { Alert, AlertDescription } from './Alert';
export type ToastVariant = 'default' | 'success' | 'error' | 'warning' | 'info';
@@ -24,7 +23,7 @@ interface ToastContextType {
const ToastContext = createContext<ToastContextType | undefined>(undefined);
export function useToast() {
export function useToast(): ToastContextType {
const context = useContext(ToastContext);
if (!context) {
throw new Error('useToast must be used within a ToastProvider');
@@ -32,15 +31,15 @@ export function useToast() {
return context;
}
export function ToastProvider({ children }: { children: ReactNode }) {
export function ToastProvider({ children }: { children: ReactNode }): JSX.Element {
const [toasts, setToasts] = useState<Toast[]>([]);
const removeToast = useCallback((id: string) => {
const removeToast = useCallback((id: string): void => {
setToasts((prev) => prev.filter((toast) => toast.id !== id));
}, []);
const addToast = useCallback(
(toast: Omit<Toast, 'id'>) => {
(toast: Omit<Toast, 'id'>): void => {
const id = Math.random().toString(36).substring(2, 9);
const newToast: Toast = {
...toast,
@@ -51,37 +50,39 @@ export function ToastProvider({ children }: { children: ReactNode }) {
setToasts((prev) => [...prev, newToast]);
if (newToast.duration && newToast.duration > 0) {
setTimeout(() => {
removeToast(id);
}, newToast.duration);
if (typeof window !== 'undefined') {
setTimeout(() => {
removeToast(id);
}, newToast.duration);
}
}
},
[removeToast]
);
const success = useCallback(
(message: string, title?: string) => {
(message: string, title?: string): void => {
addToast({ message, title, variant: 'success' });
},
[addToast]
);
const error = useCallback(
(message: string, title?: string) => {
(message: string, title?: string): void => {
addToast({ message, title, variant: 'error' });
},
[addToast]
);
const warning = useCallback(
(message: string, title?: string) => {
(message: string, title?: string): void => {
addToast({ message, title, variant: 'warning' });
},
[addToast]
);
const info = useCallback(
(message: string, title?: string) => {
(message: string, title?: string): void => {
addToast({ message, title, variant: 'info' });
},
[addToast]
@@ -95,7 +96,7 @@ export function ToastProvider({ children }: { children: ReactNode }) {
);
}
function ToastContainer({ toasts, removeToast }: { toasts: Toast[]; removeToast: (id: string) => void }) {
function ToastContainer({ toasts, removeToast }: { toasts: Toast[]; removeToast: (id: string) => void }): JSX.Element | null {
if (toasts.length === 0) return null;
return (
@@ -107,7 +108,7 @@ function ToastContainer({ toasts, removeToast }: { toasts: Toast[]; removeToast:
);
}
function ToastItem({ toast, onRemove }: { toast: Toast; onRemove: (id: string) => void }) {
function ToastItem({ toast, onRemove }: { toast: Toast; onRemove: (id: string) => void }): JSX.Element {
const variantMap: Record<ToastVariant, { alert: 'default' | 'destructive' | 'success' | 'warning'; icon: string }> = {
default: { alert: 'default', icon: '' },
success: { alert: 'success', icon: '✓' },

View File

@@ -1,7 +1,7 @@
import { type ClassValue, clsx } from 'clsx';
import { twMerge } from 'tailwind-merge';
export function cn(...inputs: ClassValue[]) {
export function cn(...inputs: ClassValue[]): string {
return twMerge(clsx(inputs));
}

View File

@@ -3,7 +3,8 @@
"compilerOptions": {
"outDir": "./dist",
"rootDir": "./src",
"jsx": "react-jsx"
"jsx": "react-jsx",
"lib": ["dom", "dom.iterable", "esnext"]
},
"include": ["src/**/*"],
"exclude": ["node_modules", "dist", "**/*.test.ts", "**/*.test.tsx", "**/*.spec.ts", "**/*.spec.tsx"]

View File

@@ -243,9 +243,14 @@ export class DSBVerifier {
});
}
const firstCredential = presentation.verifiableCredential[0];
const credentialId: string = firstCredential && 'id' in firstCredential && typeof firstCredential.id === 'string'
? firstCredential.id
: 'unknown';
return {
valid: errors.length === 0 && allValid,
credentialId: presentation.verifiableCredential[0]?.id || 'unknown',
credentialId,
credentialType: presentation.verifiableCredential.flatMap((cred) => cred.type),
verifiedAt: new Date().toISOString(),
errors: errors.length > 0 ? errors : undefined,
@@ -283,8 +288,13 @@ export class DSBVerifier {
}
// Create message to verify (credential without proof)
const documentWithoutProof = { ...document } as any;
delete documentWithoutProof.proof;
const documentObj = document as Record<string, unknown>;
const documentWithoutProof: Record<string, unknown> = {};
for (const key in documentObj) {
if (key !== 'proof') {
documentWithoutProof[key] = documentObj[key];
}
}
const message = JSON.stringify(documentWithoutProof);
// Verify signature using DID resolver
@@ -299,9 +309,9 @@ export class DSBVerifier {
/**
* Check credential status
*/
private async checkCredentialStatus(statusListId: string): Promise<'active' | 'suspended' | 'revoked' | 'expired'> {
private async checkCredentialStatus(_statusListId: string): Promise<'active' | 'suspended' | 'revoked' | 'expired'> {
// TODO: Implement status list checking
// const response = await fetch(`${this.config.statusListUrl}/${statusListId}`);
// const response = await fetch(`${this.config.statusListUrl}/${_statusListId}`);
// const statusList = await response.json();
// return statusList.status;

View File

@@ -3,8 +3,12 @@
* Supports both Temporal and AWS Step Functions
*/
// Export temporal types (these are the primary types)
export * from './temporal';
export * from './step-functions';
// Step-functions types conflict with temporal, so we only export the client
export {
getStepFunctionsWorkflowClient,
} from './step-functions';
export type WorkflowProvider = 'temporal' | 'step-functions';

View File

@@ -58,7 +58,7 @@ export class StepFunctionsWorkflowClient {
/**
* Get workflow execution status
*/
async getWorkflowStatus(executionArn: string): Promise<{
async getWorkflowStatus(_executionArn: string): Promise<{
status: 'running' | 'succeeded' | 'failed' | 'timed_out' | 'aborted';
result?: CredentialIssuanceWorkflowOutput;
error?: string;

View File

@@ -28,14 +28,9 @@ export interface CredentialIssuanceWorkflowOutput {
* In production, this would use @temporalio/client
*/
export class TemporalWorkflowClient {
private config: Required<WorkflowConfig>;
constructor(config: WorkflowConfig = {}) {
this.config = {
namespace: config.namespace || 'default',
address: config.address || 'localhost:7233',
taskQueue: config.taskQueue || 'credential-issuance',
};
constructor(_config: WorkflowConfig = {}) {
// Config stored for future use in actual Temporal implementation
void _config;
}
/**
@@ -56,7 +51,7 @@ export class TemporalWorkflowClient {
/**
* Get workflow status
*/
async getWorkflowStatus(workflowId: string): Promise<{
async getWorkflowStatus(_workflowId: string): Promise<{
status: 'running' | 'completed' | 'failed';
result?: CredentialIssuanceWorkflowOutput;
error?: string;

View File

@@ -5,7 +5,11 @@
"composite": true
},
"references": [
{ "path": "../shared" }
{ "path": "../shared" },
{ "path": "../schemas" },
{ "path": "../database" },
{ "path": "../storage" },
{ "path": "../ocr" }
],
"include": ["src/**/*"],
"exclude": ["node_modules", "dist", "**/*.test.ts", "**/*.spec.ts"]