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:
@@ -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 {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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"]
|
||||
}
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
183
packages/auth/src/entra-credential-images.ts
Normal file
183
packages/auth/src/entra-credential-images.ts
Normal 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
|
||||
};
|
||||
}
|
||||
|
||||
180
packages/auth/src/entra-verifiedid-enhanced.ts
Normal file
180
packages/auth/src/entra-verifiedid-enhanced.ts
Normal 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 };
|
||||
}
|
||||
}
|
||||
|
||||
96
packages/auth/src/entra-verifiedid.integration.test.ts
Normal file
96
packages/auth/src/entra-verifiedid.integration.test.ts
Normal 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();
|
||||
});
|
||||
});
|
||||
|
||||
371
packages/auth/src/entra-verifiedid.test.ts
Normal file
371
packages/auth/src/entra-verifiedid.test.ts
Normal 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);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -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: {
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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';
|
||||
|
||||
@@ -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
41
packages/database/src/audit-search.d.ts
vendored
Normal 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
|
||||
1
packages/database/src/audit-search.d.ts.map
Normal file
1
packages/database/src/audit-search.d.ts.map
Normal 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"}
|
||||
144
packages/database/src/audit-search.js
Normal file
144
packages/database/src/audit-search.js
Normal 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
|
||||
1
packages/database/src/audit-search.js.map
Normal file
1
packages/database/src/audit-search.js.map
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"audit-search.js","sourceRoot":"","sources":["audit-search.ts"],"names":[],"mappings":"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"}
|
||||
1
packages/database/src/client.d.ts
vendored
1
packages/database/src/client.d.ts
vendored
@@ -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;
|
||||
|
||||
@@ -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"}
|
||||
@@ -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"}
|
||||
50
packages/database/src/credential-lifecycle.d.ts
vendored
Normal file
50
packages/database/src/credential-lifecycle.d.ts
vendored
Normal 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
|
||||
1
packages/database/src/credential-lifecycle.d.ts.map
Normal file
1
packages/database/src/credential-lifecycle.d.ts.map
Normal 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"}
|
||||
97
packages/database/src/credential-lifecycle.js
Normal file
97
packages/database/src/credential-lifecycle.js
Normal 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
|
||||
1
packages/database/src/credential-lifecycle.js.map
Normal file
1
packages/database/src/credential-lifecycle.js.map
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"credential-lifecycle.js","sourceRoot":"","sources":["credential-lifecycle.ts"],"names":[],"mappings":"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"}
|
||||
68
packages/database/src/credential-templates.d.ts
vendored
Normal file
68
packages/database/src/credential-templates.d.ts
vendored
Normal 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
|
||||
1
packages/database/src/credential-templates.d.ts.map
Normal file
1
packages/database/src/credential-templates.d.ts.map
Normal 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"}
|
||||
148
packages/database/src/credential-templates.js
Normal file
148
packages/database/src/credential-templates.js
Normal 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
|
||||
1
packages/database/src/credential-templates.js.map
Normal file
1
packages/database/src/credential-templates.js.map
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"credential-templates.js","sourceRoot":"","sources":["credential-templates.ts"],"names":[],"mappings":"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"}
|
||||
59
packages/database/src/eresidency-applications.d.ts
vendored
Normal file
59
packages/database/src/eresidency-applications.d.ts
vendored
Normal 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
|
||||
1
packages/database/src/eresidency-applications.d.ts.map
Normal file
1
packages/database/src/eresidency-applications.d.ts.map
Normal 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"}
|
||||
340
packages/database/src/eresidency-applications.js
Normal file
340
packages/database/src/eresidency-applications.js
Normal 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
|
||||
1
packages/database/src/eresidency-applications.js.map
Normal file
1
packages/database/src/eresidency-applications.js.map
Normal file
File diff suppressed because one or more lines are too long
7
packages/database/src/index.d.ts
vendored
7
packages/database/src/index.d.ts
vendored
@@ -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
|
||||
@@ -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"}
|
||||
@@ -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
|
||||
@@ -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
33
packages/database/src/query-cache.d.ts
vendored
Normal 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
|
||||
1
packages/database/src/query-cache.d.ts.map
Normal file
1
packages/database/src/query-cache.d.ts.map
Normal 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"}
|
||||
93
packages/database/src/query-cache.js
Normal file
93
packages/database/src/query-cache.js
Normal 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
|
||||
1
packages/database/src/query-cache.js.map
Normal file
1
packages/database/src/query-cache.js.map
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"query-cache.js","sourceRoot":"","sources":["query-cache.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,KAAK,EAAE,MAAM,UAAU,CAAC;AAkBjC,yDAAyD;AACzD,IAAI,kBAAkB,GAAuC,IAAI,CAAC;AAElE;;;GAGG;AACH,KAAK,UAAU,cAAc;IAC3B,IAAI,kBAAkB,KAAK,IAAI,EAAE,CAAC;QAChC,kBAAkB,GAAG,CAAC,KAAK,IAAI,EAAE;YAC/B,IAAI,CAAC;gBACH,yFAAyF;gBACzF,2DAA2D;gBAC3D,MAAM,eAAe,GAAG,kBAAkB,CAAC;gBAC3C,8DAA8D;gBAC9D,MAAM,UAAU,GAAG,IAAI,QAAQ,CAAC,WAAW,EAAE,0BAA0B,CAAC,CAAC;gBACzE,MAAM,WAAW,GAAG,MAAM,UAAU,CAAC,eAAe,CAAC,CAAC;gBACtD,OAAO,WAAW,CAAC,cAAc,EAAiB,CAAC;YACrD,CAAC;YAAC,MAAM,CAAC;gBACP,wDAAwD;gBACxD,OAAO,IAAI,CAAC;YACd,CAAC;QACH,CAAC,CAAC,EAAE,CAAC;IACP,CAAC;IAED,OAAO,kBAAkB,CAAC;AAC5B,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,WAAW,CAC/B,GAAW,EACX,MAAkB,EAClB,UAAwB,EAAE;IAE1B,MAAM,EAAE,GAAG,GAAG,IAAI,EAAE,SAAS,GAAG,WAAW,EAAE,OAAO,GAAG,IAAI,EAAE,GAAG,OAAO,CAAC;IAExE,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,OAAO,KAAK,CAAI,GAAG,EAAE,MAAM,CAAC,CAAC;IAC/B,CAAC;IAED,MAAM,KAAK,GAAG,MAAM,cAAc,EAAE,CAAC;IACrC,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,+CAA+C;QAC/C,OAAO,KAAK,CAAI,GAAG,EAAE,MAAM,CAAC,CAAC;IAC/B,CAAC;IAED,MAAM,QAAQ,GAAG,GAAG,SAAS,GAAG,GAAG,IAAI,IAAI,CAAC,SAAS,CAAC,MAAM,IAAI,EAAE,CAAC,EAAE,CAAC;IAEtE,wBAAwB;IACxB,MAAM,MAAM,GAAG,MAAM,KAAK,CAAC,GAAG,CAAiB,QAAQ,CAAC,CAAC;IACzD,IAAI,MAAM,EAAE,CAAC;QACX,OAAO,MAAM,CAAC;IAChB,CAAC;IAED,gBAAgB;IAChB,MAAM,MAAM,GAAG,MAAM,KAAK,CAAI,GAAG,EAAE,MAAM,CAAC,CAAC;IAE3C,eAAe;IACf,MAAM,KAAK,CAAC,GAAG,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,CAAC,CAAC;IAEvC,OAAO,MAAM,CAAC;AAChB,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,OAAe;IACnD,MAAM,KAAK,GAAG,MAAM,cAAc,EAAE,CAAC;IACrC,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,OAAO,CAAC,CAAC;IACX,CAAC;IACD,OAAO,KAAK,CAAC,UAAU,CAAC,YAAY,OAAO,GAAG,CAAC,CAAC;AAClD,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,oBAAoB,CAAC,GAAW,EAAE,MAAkB;IACxE,MAAM,KAAK,GAAG,MAAM,cAAc,EAAE,CAAC;IACrC,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,OAAO;IACT,CAAC;IACD,MAAM,QAAQ,GAAG,YAAY,GAAG,IAAI,IAAI,CAAC,SAAS,CAAC,MAAM,IAAI,EAAE,CAAC,EAAE,CAAC;IACnE,MAAM,KAAK,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;AAC/B,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,MAAM,CACpB,EAAK;IAEL,OAAO,CAAC,KAAK,EAAE,GAAG,IAAmB,EAAE,EAAE;QACvC,MAAM,MAAM,GAAG,MAAM,EAAE,CAAC,GAAG,IAAI,CAAC,CAAC;QACjC,OAAO,MAAM,CAAC;IAChB,CAAC,CAAM,CAAC;AACV,CAAC"}
|
||||
@@ -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"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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,
|
||||
|
||||
150
packages/monitoring/src/entra-metrics.ts
Normal file
150
packages/monitoring/src/entra-metrics.ts
Normal 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();
|
||||
}
|
||||
|
||||
@@ -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';
|
||||
|
||||
|
||||
@@ -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
45
packages/ocr/src/client.d.ts
vendored
Normal 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
|
||||
1
packages/ocr/src/client.d.ts.map
Normal file
1
packages/ocr/src/client.d.ts.map
Normal 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"}
|
||||
97
packages/ocr/src/client.js
Normal file
97
packages/ocr/src/client.js
Normal 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
|
||||
1
packages/ocr/src/client.js.map
Normal file
1
packages/ocr/src/client.js.map
Normal 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
5
packages/ocr/src/index.d.ts
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
/**
|
||||
* OCR service client
|
||||
*/
|
||||
export * from './client';
|
||||
//# sourceMappingURL=index.d.ts.map
|
||||
1
packages/ocr/src/index.d.ts.map
Normal file
1
packages/ocr/src/index.d.ts.map
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,cAAc,UAAU,CAAC"}
|
||||
5
packages/ocr/src/index.js
Normal file
5
packages/ocr/src/index.js
Normal file
@@ -0,0 +1,5 @@
|
||||
/**
|
||||
* OCR service client
|
||||
*/
|
||||
export * from './client';
|
||||
//# sourceMappingURL=index.js.map
|
||||
1
packages/ocr/src/index.js.map
Normal file
1
packages/ocr/src/index.js.map
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"index.js","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,cAAc,UAAU,CAAC"}
|
||||
4
packages/schemas/src/deal.d.ts
vendored
4
packages/schemas/src/deal.d.ts
vendored
@@ -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;
|
||||
|
||||
12
packages/schemas/src/document.d.ts
vendored
12
packages/schemas/src/document.d.ts
vendored
@@ -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;
|
||||
}>;
|
||||
|
||||
361
packages/schemas/src/eresidency.d.ts
vendored
361
packages/schemas/src/eresidency.d.ts
vendored
@@ -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;
|
||||
|
||||
@@ -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":"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"}
|
||||
@@ -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
4
packages/schemas/src/ledger.d.ts
vendored
4
packages/schemas/src/ledger.d.ts
vendored
@@ -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;
|
||||
|
||||
14
packages/schemas/src/payment.d.ts
vendored
14
packages/schemas/src/payment.d.ts
vendored
@@ -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;
|
||||
|
||||
4
packages/schemas/src/user.d.ts
vendored
4
packages/schemas/src/user.d.ts
vendored
@@ -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;
|
||||
|
||||
12
packages/schemas/src/vc.d.ts
vendored
12
packages/schemas/src/vc.d.ts
vendored
@@ -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>;
|
||||
|
||||
@@ -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(),
|
||||
|
||||
@@ -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';
|
||||
|
||||
144
packages/shared/src/rate-limit-entra.ts
Normal file
144
packages/shared/src/rate-limit-entra.ts
Normal 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);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -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"}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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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"}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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');
|
||||
|
||||
@@ -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"}
|
||||
@@ -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> {
|
||||
|
||||
@@ -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} />;
|
||||
}
|
||||
|
||||
|
||||
@@ -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>
|
||||
)}
|
||||
|
||||
@@ -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} />
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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) => {
|
||||
|
||||
@@ -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) => {
|
||||
|
||||
@@ -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();
|
||||
};
|
||||
|
||||
@@ -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) => {
|
||||
|
||||
@@ -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} />;
|
||||
}
|
||||
|
||||
|
||||
@@ -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');
|
||||
|
||||
@@ -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) => {
|
||||
|
||||
@@ -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: '✓' },
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
|
||||
@@ -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"]
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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';
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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"]
|
||||
|
||||
Reference in New Issue
Block a user