/** * `products.js` —— 产品目录读取(积分套餐 + 可购权益)。 * * 产品目录,数据全来自 `billingRepo`(运营可改)。`save` 保存完整产品定义;调用方不传的 * 可选字段会按默认值或 null 入库,不做隐式局部 patch。 * * @typedef {import('./repo/index.js').BillingRepo} BillingRepo */ import { BillingError, BillingErrorCode } from './errors.js' /** * @param {BillingRepo} billingRepo */ export function createProducts(billingRepo) { return { /** @returns {Promise} */ async list() { return billingRepo.listProducts() }, async listAll() { return billingRepo.listAllProducts() }, /** * @param {string} productId * @returns {Promise} */ async get(productId) { const p = await billingRepo.findProduct(productId) return p ?? null }, /** * @param {Record} product */ async save(product) { if (!product?.id) { throw new BillingError({ code: BillingErrorCode.PRODUCT_NOT_FOUND, message: '产品 id 不能为空', retryable: false, }) } return billingRepo.saveProduct(product) }, /** * 取产品,缺失即抛(供需要强存在性的编排用,如 payment 下单)。 * @param {string} productId * @returns {Promise} */ async require(productId) { const p = await billingRepo.findProduct(productId) if (!p) { throw new BillingError({ code: BillingErrorCode.PRODUCT_NOT_FOUND, message: `产品不存在: ${productId}`, retryable: false, }) } return p }, } }