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

View File

@@ -149,7 +149,7 @@ export class TransferOrchestrator {
await this.db.markPaymentDelivered(message.order_id, txHash);
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;
}
private async publishCompleted(message: CryptoTransferRequest, log: Logger): Promise<void> {
private async publishCompleted(
message: CryptoTransferRequest,
log: Logger,
web3TransactionHash: string
): Promise<void> {
const completedMessageId = ulid();
await this.amqp.publishCompleted({
user_id: message.user_id,
order_id: message.order_id,
trace_id: message.trace_id,
message_id: completedMessageId
message_id: completedMessageId,
web3_transaction_hash: web3TransactionHash
});
log.info(
{ event: 'transfer.completed.published', message_id: completedMessageId },
{ event: 'transfer.completed.published', message_id: completedMessageId, tx_hash: web3TransactionHash },
'published crypto.transfer.completed'
);
}
@@ -228,8 +233,13 @@ export class TransferOrchestrator {
log: Logger
): Promise<void> {
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');
await this.publishCompleted(message, log);
await this.publishCompleted(message, log, txHash);
return;
}