docs: Enhance development setup documentation and update environment variable validation
- Added a new section in CURRENT_STATUS.md detailing prerequisites and quick start instructions for development setup. - Updated environment variable validation to include defaults for missing variables in env.ts. - Improved error handling in errorHandler.ts for better validation feedback. - Made various code adjustments across services to ensure robustness and clarity.
This commit is contained in:
@@ -55,5 +55,31 @@ cd orchestrator; npm run dev
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔧 Development Setup
|
||||||
|
|
||||||
|
### Prerequisites
|
||||||
|
- Node.js 18+ installed
|
||||||
|
- npm packages installed in both `webapp/` and `orchestrator/`
|
||||||
|
- `.env` file created in `orchestrator/` (minimal config is fine for dev)
|
||||||
|
|
||||||
|
### Quick Start
|
||||||
|
```powershell
|
||||||
|
# From project root
|
||||||
|
.\scripts\start-all.ps1
|
||||||
|
|
||||||
|
# Or manually:
|
||||||
|
cd webapp; npm run dev
|
||||||
|
cd orchestrator; npm run dev
|
||||||
|
```
|
||||||
|
|
||||||
|
### Status Check
|
||||||
|
```powershell
|
||||||
|
.\scripts\check-status.ps1
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
**Last Checked**: 2025-01-15
|
**Last Checked**: 2025-01-15
|
||||||
|
|
||||||
|
|||||||
76
docs/RESUME_COMPLETE.md
Normal file
76
docs/RESUME_COMPLETE.md
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
# Resume Complete - Services Status
|
||||||
|
|
||||||
|
## ✅ Completed Actions
|
||||||
|
|
||||||
|
1. **Fixed TypeScript Compilation Errors**
|
||||||
|
- Added missing imports (`AppError`, `ErrorType`, `asyncHandler`)
|
||||||
|
- Fixed database row type mismatches (snake_case to camelCase)
|
||||||
|
- Fixed optional property checks (beneficiary, plan_id, etc.)
|
||||||
|
- Fixed logger method calls in log aggregation
|
||||||
|
- Fixed health check comparison logic
|
||||||
|
- Fixed error handler for Zod validation errors
|
||||||
|
|
||||||
|
2. **Installed Missing Dependencies**
|
||||||
|
- Added `ioredis` package for Redis caching
|
||||||
|
|
||||||
|
3. **Created Configuration**
|
||||||
|
- Created minimal `.env` file for orchestrator development
|
||||||
|
|
||||||
|
4. **Verified Build**
|
||||||
|
- ✅ Orchestrator builds successfully with no TypeScript errors
|
||||||
|
|
||||||
|
5. **Started Services**
|
||||||
|
- ✅ Webapp running on http://localhost:3000
|
||||||
|
- 🔄 Orchestrator starting on http://localhost:8080
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📊 Current Status
|
||||||
|
|
||||||
|
### Webapp (Frontend)
|
||||||
|
- **Status**: ✅ Running
|
||||||
|
- **URL**: http://localhost:3000
|
||||||
|
- **Port**: 3000
|
||||||
|
|
||||||
|
### Orchestrator (Backend)
|
||||||
|
- **Status**: 🔄 Starting/Checking
|
||||||
|
- **URL**: http://localhost:8080
|
||||||
|
- **Health**: http://localhost:8080/health
|
||||||
|
- **Build**: ✅ Successful
|
||||||
|
- **Dependencies**: ✅ Installed
|
||||||
|
- **Configuration**: ✅ `.env` created
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔧 Fixed Issues
|
||||||
|
|
||||||
|
### TypeScript Compilation Errors Fixed:
|
||||||
|
1. Missing imports in `execution.ts` and `webhooks.ts`
|
||||||
|
2. Database row type mismatches in `plans.ts` and `deadLetterQueue.ts`
|
||||||
|
3. Optional property checks in `iso20022.ts`, `planValidation.ts`, `receipts.ts`
|
||||||
|
4. Logger method calls in `logAggregation.ts`
|
||||||
|
5. Health check type comparison in `health.ts`
|
||||||
|
6. Zod error handling in `errorHandler.ts`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📝 Next Steps
|
||||||
|
|
||||||
|
1. **Verify Orchestrator Health**
|
||||||
|
```powershell
|
||||||
|
Invoke-WebRequest http://localhost:8080/health
|
||||||
|
```
|
||||||
|
|
||||||
|
2. **Check Status**
|
||||||
|
```powershell
|
||||||
|
.\scripts\check-status.ps1
|
||||||
|
```
|
||||||
|
|
||||||
|
3. **View Logs**
|
||||||
|
- Check the orchestrator console window for any startup errors
|
||||||
|
- Database connection errors are expected if PostgreSQL isn't running (optional)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**Last Updated**: 2025-01-15
|
||||||
|
|
||||||
63
docs/SERVICES_RESUME.md
Normal file
63
docs/SERVICES_RESUME.md
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
# Services Resume Status
|
||||||
|
|
||||||
|
## ✅ Current Status (Resumed)
|
||||||
|
|
||||||
|
### Webapp (Frontend)
|
||||||
|
- **Status**: ✅ Running
|
||||||
|
- **URL**: http://localhost:3000
|
||||||
|
- **Port**: 3000
|
||||||
|
- **Process**: Node.js process running
|
||||||
|
|
||||||
|
### Orchestrator (Backend)
|
||||||
|
- **Status**: 🔄 Starting
|
||||||
|
- **URL**: http://localhost:8080
|
||||||
|
- **Health**: http://localhost:8080/health
|
||||||
|
- **Dependencies**: ✅ Installed
|
||||||
|
- **Configuration**: ✅ `.env` file created
|
||||||
|
- **Process**: Started in separate window
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📋 Actions Taken
|
||||||
|
|
||||||
|
1. ✅ Verified orchestrator dependencies installed
|
||||||
|
2. ✅ Created minimal `.env` configuration for orchestrator
|
||||||
|
3. ✅ Started orchestrator service in background
|
||||||
|
4. ✅ Verified webapp is running and accessible
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔍 Next Steps
|
||||||
|
|
||||||
|
### If Orchestrator Doesn't Start
|
||||||
|
|
||||||
|
1. **Check the orchestrator window** for error messages
|
||||||
|
2. **Verify Node.js version**: `node --version` (should be 18+)
|
||||||
|
3. **Check port availability**: `netstat -ano | findstr :8080`
|
||||||
|
4. **Review logs**: Check the orchestrator console window
|
||||||
|
|
||||||
|
### Manual Start
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
cd orchestrator
|
||||||
|
npm run dev
|
||||||
|
```
|
||||||
|
|
||||||
|
### Check Status
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
.\scripts\check-status.ps1
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📝 Notes
|
||||||
|
|
||||||
|
- Orchestrator requires `.env` file (minimal config is fine for development)
|
||||||
|
- PostgreSQL and Redis are optional for basic functionality
|
||||||
|
- Full database setup requires Docker for PostgreSQL/Redis
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**Last Updated**: 2025-01-15
|
||||||
|
|
||||||
63
docs/SERVICES_RUNNING.md
Normal file
63
docs/SERVICES_RUNNING.md
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
# Services Running Status
|
||||||
|
|
||||||
|
## ✅ All Services Operational
|
||||||
|
|
||||||
|
### Webapp (Frontend)
|
||||||
|
- **Status**: ✅ Running
|
||||||
|
- **URL**: http://localhost:3000
|
||||||
|
- **Port**: 3000
|
||||||
|
- **Technology**: Next.js
|
||||||
|
|
||||||
|
### Orchestrator (Backend)
|
||||||
|
- **Status**: ✅ Running
|
||||||
|
- **URL**: http://localhost:8080
|
||||||
|
- **Health**: http://localhost:8080/health
|
||||||
|
- **Port**: 8080
|
||||||
|
- **Technology**: Express.js + TypeScript
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔧 Issues Resolved
|
||||||
|
|
||||||
|
1. **TypeScript Compilation Errors** ✅
|
||||||
|
- Fixed missing imports
|
||||||
|
- Fixed type mismatches
|
||||||
|
- Fixed optional property checks
|
||||||
|
- Fixed logger method calls
|
||||||
|
|
||||||
|
2. **Missing Dependencies** ✅
|
||||||
|
- Installed `ioredis` for Redis
|
||||||
|
- Installed `dotenv` for environment variables
|
||||||
|
|
||||||
|
3. **Environment Configuration** ✅
|
||||||
|
- Created `.env` file with minimal dev config
|
||||||
|
- Fixed environment validation to use defaults
|
||||||
|
- Added dotenv loading
|
||||||
|
|
||||||
|
4. **Build Process** ✅
|
||||||
|
- Orchestrator builds successfully
|
||||||
|
- All TypeScript errors resolved
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📝 Quick Commands
|
||||||
|
|
||||||
|
### Check Status
|
||||||
|
```powershell
|
||||||
|
.\scripts\check-status.ps1
|
||||||
|
```
|
||||||
|
|
||||||
|
### Start Services
|
||||||
|
```powershell
|
||||||
|
.\scripts\start-all.ps1
|
||||||
|
```
|
||||||
|
|
||||||
|
### Access Services
|
||||||
|
- Frontend: http://localhost:3000
|
||||||
|
- Backend API: http://localhost:8080
|
||||||
|
- Health Check: http://localhost:8080/health
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**Last Updated**: 2025-01-15
|
||||||
|
|
||||||
@@ -11,25 +11,26 @@
|
|||||||
"migrate": "ts-node src/db/migrations/index.ts"
|
"migrate": "ts-node src/db/migrations/index.ts"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"express": "^4.18.2",
|
|
||||||
"uuid": "^9.0.1",
|
|
||||||
"cors": "^2.8.5",
|
"cors": "^2.8.5",
|
||||||
|
"dotenv": "^17.2.3",
|
||||||
|
"express": "^4.18.2",
|
||||||
"express-rate-limit": "^7.1.5",
|
"express-rate-limit": "^7.1.5",
|
||||||
"helmet": "^7.1.0",
|
"helmet": "^7.1.0",
|
||||||
"zod": "^3.22.4",
|
"ioredis": "^5.8.2",
|
||||||
"pg": "^8.11.3",
|
"pg": "^8.11.3",
|
||||||
"pino": "^8.16.2",
|
"pino": "^8.16.2",
|
||||||
"pino-pretty": "^10.2.3",
|
"pino-pretty": "^10.2.3",
|
||||||
"prom-client": "^15.1.0"
|
"prom-client": "^15.1.0",
|
||||||
|
"uuid": "^9.0.1",
|
||||||
|
"zod": "^3.22.4"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@types/cors": "^2.8.17",
|
||||||
"@types/express": "^4.17.21",
|
"@types/express": "^4.17.21",
|
||||||
"@types/node": "^20.10.0",
|
"@types/node": "^20.10.0",
|
||||||
"@types/uuid": "^9.0.6",
|
|
||||||
"@types/cors": "^2.8.17",
|
|
||||||
"@types/pg": "^8.10.9",
|
"@types/pg": "^8.10.9",
|
||||||
"typescript": "^5.3.3",
|
"@types/uuid": "^9.0.6",
|
||||||
"ts-node": "^10.9.2"
|
"ts-node": "^10.9.2",
|
||||||
|
"typescript": "^5.3.3"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { Request, Response } from "express";
|
import { Request, Response } from "express";
|
||||||
import { executionCoordinator } from "../services/execution";
|
import { executionCoordinator } from "../services/execution";
|
||||||
import { asyncHandler } from "../services/errorHandler";
|
import { asyncHandler, AppError, ErrorType } from "../services/errorHandler";
|
||||||
import { auditLog } from "../middleware";
|
import { auditLog } from "../middleware";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { Request, Response } from "express";
|
import { Request, Response } from "express";
|
||||||
import { executionCoordinator } from "../services/execution";
|
import { executionCoordinator } from "../services/execution";
|
||||||
import { logger } from "../logging/logger";
|
import { logger } from "../logging/logger";
|
||||||
|
import { asyncHandler, AppError, ErrorType } from "../services/errorHandler";
|
||||||
|
|
||||||
interface WebhookConfig {
|
interface WebhookConfig {
|
||||||
url: string;
|
url: string;
|
||||||
|
|||||||
@@ -41,7 +41,22 @@ export const env = envSchema.parse({
|
|||||||
*/
|
*/
|
||||||
export function validateEnv() {
|
export function validateEnv() {
|
||||||
try {
|
try {
|
||||||
envSchema.parse(process.env);
|
// Use same defaults as env object
|
||||||
|
const envWithDefaults = {
|
||||||
|
NODE_ENV: process.env.NODE_ENV || "development",
|
||||||
|
PORT: process.env.PORT || "8080",
|
||||||
|
DATABASE_URL: process.env.DATABASE_URL,
|
||||||
|
API_KEYS: process.env.API_KEYS,
|
||||||
|
REDIS_URL: process.env.REDIS_URL,
|
||||||
|
LOG_LEVEL: process.env.LOG_LEVEL || "info",
|
||||||
|
ALLOWED_IPS: process.env.ALLOWED_IPS,
|
||||||
|
SESSION_SECRET: process.env.SESSION_SECRET || "dev-secret-change-in-production-min-32-chars",
|
||||||
|
JWT_SECRET: process.env.JWT_SECRET,
|
||||||
|
AZURE_KEY_VAULT_URL: process.env.AZURE_KEY_VAULT_URL,
|
||||||
|
AWS_SECRETS_MANAGER_REGION: process.env.AWS_SECRETS_MANAGER_REGION,
|
||||||
|
SENTRY_DSN: process.env.SENTRY_DSN,
|
||||||
|
};
|
||||||
|
envSchema.parse(envWithDefaults);
|
||||||
console.log("✅ Environment variables validated");
|
console.log("✅ Environment variables validated");
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (error instanceof z.ZodError) {
|
if (error instanceof z.ZodError) {
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ export async function storePlan(plan: Plan): Promise<void> {
|
|||||||
* Get plan by ID
|
* Get plan by ID
|
||||||
*/
|
*/
|
||||||
export async function getPlanById(planId: string): Promise<Plan | null> {
|
export async function getPlanById(planId: string): Promise<Plan | null> {
|
||||||
const result = await query<Plan>(
|
const result = await query<any>(
|
||||||
"SELECT * FROM plans WHERE plan_id = $1",
|
"SELECT * FROM plans WHERE plan_id = $1",
|
||||||
[planId]
|
[planId]
|
||||||
);
|
);
|
||||||
@@ -52,7 +52,7 @@ export async function getPlanById(planId: string): Promise<Plan | null> {
|
|||||||
maxLTV: row.max_ltv,
|
maxLTV: row.max_ltv,
|
||||||
signature: row.signature,
|
signature: row.signature,
|
||||||
plan_hash: row.plan_hash,
|
plan_hash: row.plan_hash,
|
||||||
created_at: row.created_at?.toISOString(),
|
created_at: row.created_at ? (row.created_at instanceof Date ? row.created_at.toISOString() : String(row.created_at)) : undefined,
|
||||||
status: row.status,
|
status: row.status,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -57,7 +57,7 @@ export async function healthCheck(): Promise<HealthStatus> {
|
|||||||
const allHealthy =
|
const allHealthy =
|
||||||
checks.database === "up" &&
|
checks.database === "up" &&
|
||||||
checks.memory !== "critical" &&
|
checks.memory !== "critical" &&
|
||||||
checks.disk !== "critical" &&
|
(checks.disk === "ok" || checks.disk === "warning") &&
|
||||||
dependencies.every((d) => d.status === "healthy");
|
dependencies.every((d) => d.status === "healthy");
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import "dotenv/config";
|
||||||
import express from "express";
|
import express from "express";
|
||||||
import cors from "cors";
|
import cors from "cors";
|
||||||
import { validateEnv } from "./config/env";
|
import { validateEnv } from "./config/env";
|
||||||
|
|||||||
@@ -33,7 +33,23 @@ export class ELKAggregator implements LogAggregator {
|
|||||||
// });
|
// });
|
||||||
|
|
||||||
// For now, just log normally
|
// For now, just log normally
|
||||||
logger[level as keyof typeof logger](metadata || {}, message);
|
const meta = metadata || {};
|
||||||
|
switch (level) {
|
||||||
|
case "error":
|
||||||
|
logger.error(meta, message);
|
||||||
|
break;
|
||||||
|
case "warn":
|
||||||
|
logger.warn(meta, message);
|
||||||
|
break;
|
||||||
|
case "info":
|
||||||
|
logger.info(meta, message);
|
||||||
|
break;
|
||||||
|
case "debug":
|
||||||
|
logger.debug(meta, message);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
logger.info(meta, message);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -61,7 +77,24 @@ export class DatadogAggregator implements LogAggregator {
|
|||||||
// }),
|
// }),
|
||||||
// });
|
// });
|
||||||
|
|
||||||
logger[level as keyof typeof logger](metadata || {}, message);
|
// For now, just log normally
|
||||||
|
const meta = metadata || {};
|
||||||
|
switch (level) {
|
||||||
|
case "error":
|
||||||
|
logger.error(meta, message);
|
||||||
|
break;
|
||||||
|
case "warn":
|
||||||
|
logger.warn(meta, message);
|
||||||
|
break;
|
||||||
|
case "info":
|
||||||
|
logger.info(meta, message);
|
||||||
|
break;
|
||||||
|
case "debug":
|
||||||
|
logger.debug(meta, message);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
logger.info(meta, message);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ export interface Alert {
|
|||||||
title: string;
|
title: string;
|
||||||
message: string;
|
message: string;
|
||||||
metadata?: any;
|
metadata?: any;
|
||||||
|
timestamp?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class AlertingService {
|
export class AlertingService {
|
||||||
@@ -90,7 +91,7 @@ export class AlertingService {
|
|||||||
*/
|
*/
|
||||||
private shouldThrottle(alert: Alert): boolean {
|
private shouldThrottle(alert: Alert): boolean {
|
||||||
const recentAlerts = this.alertHistory.filter(
|
const recentAlerts = this.alertHistory.filter(
|
||||||
(a) => Date.now() - new Date(a.timestamp).getTime() < 5 * 60 * 1000 // 5 minutes
|
(a) => a.timestamp && Date.now() - new Date(a.timestamp).getTime() < 5 * 60 * 1000 // 5 minutes
|
||||||
);
|
);
|
||||||
|
|
||||||
// Throttle if more than 10 alerts in 5 minutes
|
// Throttle if more than 10 alerts in 5 minutes
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ export async function addToDLQ(
|
|||||||
* Get messages from DLQ for retry
|
* Get messages from DLQ for retry
|
||||||
*/
|
*/
|
||||||
export async function getDLQMessages(queue: string, limit = 10): Promise<DeadLetterMessage[]> {
|
export async function getDLQMessages(queue: string, limit = 10): Promise<DeadLetterMessage[]> {
|
||||||
const result = await query<DeadLetterMessage>(
|
const result = await query<any>(
|
||||||
`SELECT * FROM dead_letter_queue
|
`SELECT * FROM dead_letter_queue
|
||||||
WHERE queue = $1 AND retry_count < 3
|
WHERE queue = $1 AND retry_count < 3
|
||||||
ORDER BY created_at ASC
|
ORDER BY created_at ASC
|
||||||
@@ -38,13 +38,13 @@ export async function getDLQMessages(queue: string, limit = 10): Promise<DeadLet
|
|||||||
[queue, limit]
|
[queue, limit]
|
||||||
);
|
);
|
||||||
|
|
||||||
return result.map((row) => ({
|
return result.map((row: any) => ({
|
||||||
messageId: row.message_id,
|
messageId: row.message_id,
|
||||||
originalQueue: row.queue,
|
originalQueue: row.queue,
|
||||||
payload: typeof row.payload === "string" ? JSON.parse(row.payload) : row.payload,
|
payload: typeof row.payload === "string" ? JSON.parse(row.payload) : row.payload,
|
||||||
error: row.error,
|
error: row.error,
|
||||||
retryCount: row.retry_count,
|
retryCount: row.retry_count,
|
||||||
createdAt: row.created_at,
|
createdAt: row.created_at ? (row.created_at instanceof Date ? row.created_at.toISOString() : String(row.created_at)) : new Date().toISOString(),
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -59,7 +59,8 @@ export function errorHandler(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Handle validation errors
|
// Handle validation errors
|
||||||
if (err.name === "ValidationError" || err.name === "ZodError" || err.issues) {
|
const isZodError = err.name === "ZodError" || (err as any).issues;
|
||||||
|
if (err.name === "ValidationError" || isZodError) {
|
||||||
logger.warn({
|
logger.warn({
|
||||||
error: err,
|
error: err,
|
||||||
requestId,
|
requestId,
|
||||||
@@ -69,7 +70,7 @@ export function errorHandler(
|
|||||||
return res.status(400).json({
|
return res.status(400).json({
|
||||||
error: ErrorType.VALIDATION_ERROR,
|
error: ErrorType.VALIDATION_ERROR,
|
||||||
message: "Validation failed",
|
message: "Validation failed",
|
||||||
details: err.message || err.issues,
|
details: err.message || (isZodError ? (err as any).issues : undefined),
|
||||||
requestId,
|
requestId,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -81,15 +81,15 @@ export async function generatePacs008(plan: Plan): Promise<string> {
|
|||||||
},
|
},
|
||||||
CdtrAgt: {
|
CdtrAgt: {
|
||||||
FinInstnId: {
|
FinInstnId: {
|
||||||
BICFI: payStep.beneficiary.BIC || "UNKNOWN",
|
BICFI: payStep.beneficiary?.BIC || "UNKNOWN",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Cdtr: {
|
Cdtr: {
|
||||||
Nm: payStep.beneficiary.name || "Unknown",
|
Nm: payStep.beneficiary?.name || "Unknown",
|
||||||
},
|
},
|
||||||
CdtrAcct: {
|
CdtrAcct: {
|
||||||
Id: {
|
Id: {
|
||||||
IBAN: payStep.beneficiary.IBAN || "",
|
IBAN: payStep.beneficiary?.IBAN || "",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
RmtInf: {
|
RmtInf: {
|
||||||
|
|||||||
@@ -115,9 +115,9 @@ export function checkStepDependencies(steps: PlanStep[]): ValidationResult {
|
|||||||
function getStepOutput(step: PlanStep): { asset: string; amount: number } | null {
|
function getStepOutput(step: PlanStep): { asset: string; amount: number } | null {
|
||||||
switch (step.type) {
|
switch (step.type) {
|
||||||
case "borrow":
|
case "borrow":
|
||||||
return { asset: step.asset, amount: step.amount };
|
return step.asset ? { asset: step.asset, amount: step.amount } : null;
|
||||||
case "swap":
|
case "swap":
|
||||||
return { asset: step.to, amount: step.amount };
|
return step.to ? { asset: step.to, amount: step.amount } : null;
|
||||||
default:
|
default:
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,6 +29,9 @@ export interface Receipt {
|
|||||||
* Generate receipt for a plan execution
|
* Generate receipt for a plan execution
|
||||||
*/
|
*/
|
||||||
export async function generateReceipt(plan: Plan): Promise<Receipt> {
|
export async function generateReceipt(plan: Plan): Promise<Receipt> {
|
||||||
|
if (!plan.plan_id) {
|
||||||
|
throw new Error("Plan ID is required");
|
||||||
|
}
|
||||||
const notaryProof = await getNotaryProof(plan.plan_id);
|
const notaryProof = await getNotaryProof(plan.plan_id);
|
||||||
const dltStatus = await getDLTStatus(plan.plan_id);
|
const dltStatus = await getDLTStatus(plan.plan_id);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user