import { createHttpError } from '../../utils/http.js' import { assertOpen91Config } from './config.js' type JsonObject = Record export function normalizeOpen91String(value: unknown) { return String(value || '').trim() } export function normalizeOpen91CreatePayload(payload: JsonObject = {}) { return { orderNo: normalizeOpen91String(payload.orderNo), productNo: normalizeOpen91String(payload.productNo), buyNum: normalizeOpen91BuyNum(payload.buyNum), maxAmount: normalizeOpen91OptionalAmount(payload.maxAmount), callbackUrl: normalizeOpen91String(payload.callbackUrl), timestamp: normalizeOpen91Timestamp(payload.timestamp), version: normalizeOpen91String(payload.version), sign: normalizeOpen91String(payload.sign).toUpperCase(), } } export function normalizeOpen91QueryPayload(payload: JsonObject = {}) { return { orderNo: normalizeOpen91String(payload.orderNo), timestamp: normalizeOpen91Timestamp(payload.timestamp), version: normalizeOpen91String(payload.version), sign: normalizeOpen91String(payload.sign).toUpperCase(), } } export function assertOpen91CreatePayload(payload: JsonObject, config = assertOpen91Config()) { if (!payload.orderNo) { throw createHttpError('缺少 orderNo', { statusCode: 400, errorCode: 'open91_missing_order_no', }) } if (!payload.productNo) { throw createHttpError('缺少 productNo', { statusCode: 400, errorCode: 'open91_missing_product_no', }) } if (!Number.isInteger(payload.buyNum) || payload.buyNum <= 0) { throw createHttpError('buyNum 必须是大于 0 的整数', { statusCode: 400, errorCode: 'open91_invalid_buy_num', }) } assertOpen91CommonPayload(payload, config) } export function assertOpen91QueryPayload(payload: JsonObject, config = assertOpen91Config()) { if (!payload.orderNo) { throw createHttpError('缺少 orderNo', { statusCode: 400, errorCode: 'open91_missing_order_no', }) } assertOpen91CommonPayload(payload, config) } export function assertOpen91Timestamp(timestamp: unknown, toleranceSeconds = assertOpen91Config().timestampToleranceSeconds) { const nowSeconds = Math.floor(Date.now() / 1000) if (Math.abs(nowSeconds - Number(timestamp)) > Math.max(1, Number(toleranceSeconds) || 600)) { throw createHttpError('timestamp 已过期', { statusCode: 400, errorCode: 'open91_expired_timestamp', }) } } function assertOpen91CommonPayload(payload: JsonObject, config: JsonObject) { if (!payload.timestamp) { throw createHttpError('缺少 timestamp', { statusCode: 400, errorCode: 'open91_missing_timestamp', }) } if (!payload.version) { throw createHttpError('缺少 version', { statusCode: 400, errorCode: 'open91_missing_version', }) } if (payload.version !== config.version) { throw createHttpError(`version 不匹配,当前仅支持 ${config.version}`, { statusCode: 400, errorCode: 'open91_invalid_version', }) } if (!payload.sign) { throw createHttpError('缺少 sign', { statusCode: 400, errorCode: 'open91_missing_sign', }) } } function normalizeOpen91BuyNum(value: unknown) { const parsed = Number(value) return Number.isInteger(parsed) ? parsed : 0 } function normalizeOpen91OptionalAmount(value: unknown) { const normalized = normalizeOpen91String(value) if (!normalized) { return '' } if (!/^\d+(?:\.\d+)?$/.test(normalized)) { throw createHttpError('maxAmount 格式无效', { statusCode: 400, errorCode: 'open91_invalid_max_amount', }) } return normalized } function normalizeOpen91Timestamp(value: unknown) { const normalized = normalizeOpen91String(value) if (!/^\d{10}$/.test(normalized)) { return 0 } return Number(normalized) }