feat: update

This commit is contained in:
2026-05-14 01:36:30 +03:00
parent c1a6c15773
commit 550061c4da
2 changed files with 25 additions and 12 deletions

View File

@@ -10,27 +10,30 @@ export interface CryptoTransferCompleted {
order_id: string; order_id: string;
trace_id: string; trace_id: string;
message_id: string; message_id: string;
web3_transaction_hash: string;
} }
const ULID_REGEX = /^[0-9A-HJKMNP-TV-Z]{26}$/; const ULID_REGEX = /^[0-9A-HJKMNP-TV-Z]{26}$/;
export function parseCryptoTransferRequest(raw: unknown): CryptoTransferRequest { export function parseCryptoTransferRequest(raw: unknown): CryptoTransferRequest {
if (!raw || typeof raw !== "object" || Array.isArray(raw)) { if (!raw || typeof raw !== 'object' || Array.isArray(raw)) {
throw new Error("message body must be a JSON object"); throw new Error('message body must be a JSON object');
} }
const candidate = raw as Record<string, unknown>; const candidate = raw as Record<string, unknown>;
return { return {
order_id: requireUlid(candidate, "order_id"), order_id: requireUlid(candidate, 'order_id'),
user_id: requireUlid(candidate, "user_id"), user_id: requireUlid(candidate, 'user_id'),
trace_id: requireUlid(candidate, "trace_id"), trace_id: requireUlid(candidate, 'trace_id'),
message_id: requireUlid(candidate, "message_id") message_id: requireUlid(candidate, 'message_id')
}; };
} }
function requireUlid(source: Record<string, unknown>, key: string): string { function requireUlid(source: Record<string, unknown>, key: string): string {
const value = source[key]; const value = source[key];
if (typeof value !== "string" || !ULID_REGEX.test(value)) { if (typeof value !== 'string' || !ULID_REGEX.test(value)) {
throw new Error(`field '${key}' must be a ULID string`); throw new Error(`field '${key}' must be a ULID string`);
} }
return value; return value;

View File

@@ -149,7 +149,7 @@ export class TransferOrchestrator {
await this.db.markPaymentDelivered(message.order_id, txHash); await this.db.markPaymentDelivered(message.order_id, txHash);
log.info({ event: 'transfer.delivered', tx_hash: txHash }, 'marked usdt_delivered'); log.info({ event: 'transfer.delivered', tx_hash: txHash }, 'marked usdt_delivered');
await this.publishCompleted(message, log); await this.publishCompleted(message, log, txHash);
}); });
} }
@@ -208,16 +208,21 @@ export class TransferOrchestrator {
return false; return false;
} }
private async publishCompleted(message: CryptoTransferRequest, log: Logger): Promise<void> { private async publishCompleted(
message: CryptoTransferRequest,
log: Logger,
web3TransactionHash: string
): Promise<void> {
const completedMessageId = ulid(); const completedMessageId = ulid();
await this.amqp.publishCompleted({ await this.amqp.publishCompleted({
user_id: message.user_id, user_id: message.user_id,
order_id: message.order_id, order_id: message.order_id,
trace_id: message.trace_id, trace_id: message.trace_id,
message_id: completedMessageId message_id: completedMessageId,
web3_transaction_hash: web3TransactionHash
}); });
log.info( log.info(
{ event: 'transfer.completed.published', message_id: completedMessageId }, { event: 'transfer.completed.published', message_id: completedMessageId, tx_hash: web3TransactionHash },
'published crypto.transfer.completed' 'published crypto.transfer.completed'
); );
} }
@@ -228,8 +233,13 @@ export class TransferOrchestrator {
log: Logger log: Logger
): Promise<void> { ): Promise<void> {
if (existing.status === 'usdt_delivered') { if (existing.status === 'usdt_delivered') {
const txHash = existing.web3_transaction_hash;
if (!txHash) {
log.error({ event: 'payment.delivered_missing_hash' }, 'usdt_delivered but web3_transaction_hash is null');
return;
}
log.info({ event: 'payment.already_delivered' }, 'already delivered, publishing completion'); log.info({ event: 'payment.already_delivered' }, 'already delivered, publishing completion');
await this.publishCompleted(message, log); await this.publishCompleted(message, log, txHash);
return; return;
} }