后端迁移快手电子券平台服务

This commit is contained in:
yml
2026-05-21 17:15:58 +08:00
parent 807c0f95e9
commit 717866e5fb
6 changed files with 162 additions and 59 deletions
@@ -1,10 +1,23 @@
// @ts-check
import { createHttpError } from '../../../utils/http.js' import { createHttpError } from '../../../utils/http.js'
import { kuaishouEticketRequest } from './http-client.js' import { kuaishouEticketRequest } from './http-client.js'
import { resolveKuaishouEticketConfig } from './shared.js' import { resolveKuaishouEticketConfig } from './shared.js'
export async function queryKuaishouEticketConsumeDetail(payload = {}) { type JsonObject = Record<string, any>
type KuaishouEticketDetailPayload = {
eTicketId: string
oid: string
formToken: string
leftCount: number
[key: string]: unknown
}
type KuaishouEticketDetailResult = {
detail: KuaishouEticketDetailPayload | null
[key: string]: any
}
export async function queryKuaishouEticketConsumeDetail(payload: JsonObject = {}) {
const context = resolveKuaishouEticketActionContext(payload) const context = resolveKuaishouEticketActionContext(payload)
const response = await kuaishouEticketRequest(context.detailPath, { const response = await kuaishouEticketRequest(context.detailPath, {
baseUrl: context.baseUrl, baseUrl: context.baseUrl,
@@ -21,7 +34,7 @@ export async function queryKuaishouEticketConsumeDetail(payload = {}) {
}) })
} }
export async function consumeKuaishouEticket(payload = {}) { export async function consumeKuaishouEticket(payload: JsonObject = {}) {
const context = resolveKuaishouEticketActionContext(payload) const context = resolveKuaishouEticketActionContext(payload)
const detailResult = shouldResolveConsumeDetail(payload) const detailResult = shouldResolveConsumeDetail(payload)
? await queryKuaishouEticketConsumeDetail({ ? await queryKuaishouEticketConsumeDetail({
@@ -51,7 +64,7 @@ export async function consumeKuaishouEticket(payload = {}) {
}) })
} }
export function mapKuaishouEticketDetailResult(payload = {}, context = {}) { export function mapKuaishouEticketDetailResult(payload: JsonObject = {}, context: JsonObject = {}) {
const normalized = normalizeKuaishouEticketApiResult(payload) const normalized = normalizeKuaishouEticketApiResult(payload)
const detail = mapKuaishouEticketDetailPayload(payload?.data?.eTicket) const detail = mapKuaishouEticketDetailPayload(payload?.data?.eTicket)
const goods = mapKuaishouEticketGoodsPayload(payload?.data?.goods) const goods = mapKuaishouEticketGoodsPayload(payload?.data?.goods)
@@ -71,7 +84,7 @@ export function mapKuaishouEticketDetailResult(payload = {}, context = {}) {
} }
} }
export function mapKuaishouEticketConsumeResult(payload = {}, context = {}) { export function mapKuaishouEticketConsumeResult(payload: JsonObject = {}, context: JsonObject = {}) {
const normalized = normalizeKuaishouEticketApiResult(payload) const normalized = normalizeKuaishouEticketApiResult(payload)
return { return {
@@ -93,7 +106,10 @@ export function mapKuaishouEticketConsumeResult(payload = {}, context = {}) {
} }
} }
export function resolveKuaishouEticketConsumePayload(payload = {}, detailResult = null) { export function resolveKuaishouEticketConsumePayload(
payload: JsonObject = {},
detailResult: KuaishouEticketDetailResult | null = null,
) {
const detail = detailResult?.detail || null const detail = detailResult?.detail || null
const eTicketId = pickFirstNonEmpty([payload.eTicketId, detail?.eTicketId]) const eTicketId = pickFirstNonEmpty([payload.eTicketId, detail?.eTicketId])
const oid = pickFirstNonEmpty([payload.oid, detail?.oid]) const oid = pickFirstNonEmpty([payload.oid, detail?.oid])
@@ -131,7 +147,7 @@ export function resolveKuaishouEticketConsumePayload(payload = {}, detailResult
} }
} }
export function normalizeKuaishouEticketApiResult(payload = {}) { export function normalizeKuaishouEticketApiResult(payload: JsonObject = {}) {
const result = Number(payload?.result || 0) const result = Number(payload?.result || 0)
return { return {
@@ -143,7 +159,7 @@ export function normalizeKuaishouEticketApiResult(payload = {}) {
} }
} }
export function mapKuaishouEticketDetailPayload(value = {}) { export function mapKuaishouEticketDetailPayload(value: unknown): KuaishouEticketDetailPayload | null {
if (!isPlainObject(value)) { if (!isPlainObject(value)) {
return null return null
} }
@@ -164,7 +180,7 @@ export function mapKuaishouEticketDetailPayload(value = {}) {
} }
} }
export function mapKuaishouEticketGoodsPayload(value = {}) { export function mapKuaishouEticketGoodsPayload(value: unknown) {
if (!isPlainObject(value)) { if (!isPlainObject(value)) {
return null return null
} }
@@ -179,7 +195,7 @@ export function mapKuaishouEticketGoodsPayload(value = {}) {
} }
} }
function resolveKuaishouEticketActionContext(payload = {}) { function resolveKuaishouEticketActionContext(payload: JsonObject = {}) {
const config = resolveKuaishouEticketConfig(payload) const config = resolveKuaishouEticketConfig(payload)
const eTicketId = String(payload.eTicketId || '').trim() const eTicketId = String(payload.eTicketId || '').trim()
@@ -203,11 +219,11 @@ function resolveKuaishouEticketActionContext(payload = {}) {
} }
} }
function shouldResolveConsumeDetail(payload = {}) { function shouldResolveConsumeDetail(payload: JsonObject = {}): boolean {
return !String(payload.oid || '').trim() || !String(payload.formToken || '').trim() return !String(payload.oid || '').trim() || !String(payload.formToken || '').trim()
} }
function pickFirstNonEmpty(values) { function pickFirstNonEmpty(values: unknown[]): string {
for (const value of values) { for (const value of values) {
const normalized = String(value || '').trim() const normalized = String(value || '').trim()
if (normalized) { if (normalized) {
@@ -218,16 +234,16 @@ function pickFirstNonEmpty(values) {
return '' return ''
} }
function normalizePositiveInteger(value, fallback) { function normalizePositiveInteger(value: unknown, fallback: number): number {
const parsed = Number(value) const parsed = Number(value)
return Number.isInteger(parsed) && parsed > 0 ? parsed : fallback return Number.isInteger(parsed) && parsed > 0 ? parsed : fallback
} }
function normalizeInteger(value, fallback) { function normalizeInteger(value: unknown, fallback: number): number {
const parsed = Number(value) const parsed = Number(value)
return Number.isInteger(parsed) ? parsed : fallback return Number.isInteger(parsed) ? parsed : fallback
} }
function isPlainObject(value) { function isPlainObject(value: unknown): value is JsonObject {
return Object.prototype.toString.call(value) === '[object Object]' return Object.prototype.toString.call(value) === '[object Object]'
} }
@@ -1,14 +1,35 @@
// @ts-check
import http from 'node:http' import http from 'node:http'
import https from 'node:https' import https from 'node:https'
import type { IncomingHttpHeaders } from 'node:http'
import { parseJsonObject } from '../../../utils/json.js' import { parseJsonObject } from '../../../utils/json.js'
import { createHttpError } from '../../../utils/http.js' import { createHttpError } from '../../../utils/http.js'
import { logInfo } from '../../../utils/logger.js' import { logInfo } from '../../../utils/logger.js'
import { buildKuaishouEticketHeaders, buildKuaishouEticketUrl, resolveKuaishouEticketConfig } from './shared.js' import { buildKuaishouEticketHeaders, buildKuaishouEticketUrl, resolveKuaishouEticketConfig } from './shared.js'
export async function kuaishouEticketRequest(pathname, options = {}) { type JsonObject = Record<string, any>
type KuaishouEticketRequestOptions = JsonObject & {
method?: string
body?: unknown
headers?: Record<string, unknown>
timeoutMs?: number | string
cookie?: string
contentType?: string | null
}
type HeaderAdapter = {
get(name: string): string | null
}
type NodeHttpResponse = {
ok: boolean
status: number
headers: HeaderAdapter
bodyText: string
}
export async function kuaishouEticketRequest(pathname: string, options: KuaishouEticketRequestOptions = {}) {
const config = resolveKuaishouEticketConfig(options) const config = resolveKuaishouEticketConfig(options)
const url = buildKuaishouEticketUrl(config.baseUrl, pathname) const url = buildKuaishouEticketUrl(config.baseUrl, pathname)
const timeoutMs = Number(options.timeoutMs || config.timeoutMs || 8000) const timeoutMs = Number(options.timeoutMs || config.timeoutMs || 8000)
@@ -69,7 +90,7 @@ export async function kuaishouEticketRequest(pathname, options = {}) {
} }
} }
function inferContentType(body) { function inferContentType(body: unknown): string {
if (body == null) { if (body == null) {
return '' return ''
} }
@@ -81,7 +102,7 @@ function inferContentType(body) {
return 'application/json' return 'application/json'
} }
function normalizeRequestBody(body, contentType) { function normalizeRequestBody(body: unknown, contentType: unknown): string | undefined {
if (body == null) { if (body == null) {
return undefined return undefined
} }
@@ -97,7 +118,15 @@ function normalizeRequestBody(body, contentType) {
return String(body) return String(body)
} }
async function requestViaNodeHttp(url, { method, headers, body, signal }) { async function requestViaNodeHttp(
url: URL,
{ method, headers, body, signal }: {
method: string
headers: Record<string, string>
body?: string
signal: AbortSignal
},
): Promise<NodeHttpResponse> {
const isHttps = url.protocol === 'https:' const isHttps = url.protocol === 'https:'
const transport = isHttps ? https : http const transport = isHttps ? https : http
@@ -107,7 +136,7 @@ async function requestViaNodeHttp(url, { method, headers, body, signal }) {
headers, headers,
rejectUnauthorized: false, rejectUnauthorized: false,
}, (response) => { }, (response) => {
const chunks = [] const chunks: Buffer[] = []
response.on('data', (chunk) => { response.on('data', (chunk) => {
chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk)) chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk))
@@ -148,8 +177,8 @@ async function requestViaNodeHttp(url, { method, headers, body, signal }) {
}) })
} }
function createHeaderAdapter(headers) { function createHeaderAdapter(headers: IncomingHttpHeaders): HeaderAdapter {
const normalized = new Map() const normalized = new Map<string, string>()
for (const [key, value] of Object.entries(headers || {})) { for (const [key, value] of Object.entries(headers || {})) {
if (Array.isArray(value)) { if (Array.isArray(value)) {
@@ -163,7 +192,7 @@ function createHeaderAdapter(headers) {
} }
return { return {
get(name) { get(name: string) {
return normalized.get(String(name || '').toLowerCase()) || null return normalized.get(String(name || '').toLowerCase()) || null
}, },
} }
@@ -1,10 +1,10 @@
// @ts-check
import { createHttpError } from '../../../utils/http.js' import { createHttpError } from '../../../utils/http.js'
import { kuaishouEticketRequest } from './http-client.js' import { kuaishouEticketRequest } from './http-client.js'
import { resolveKuaishouEticketConfig } from './shared.js' import { resolveKuaishouEticketConfig } from './shared.js'
export async function queryKuaishouEticketStableInfo(payload = {}) { type JsonObject = Record<string, any>
export async function queryKuaishouEticketStableInfo(payload: JsonObject = {}) {
const config = resolveKuaishouEticketConfig(payload) const config = resolveKuaishouEticketConfig(payload)
const cookie = String(payload.cookie || config.cookie || '').trim() const cookie = String(payload.cookie || config.cookie || '').trim()
@@ -29,7 +29,7 @@ export async function queryKuaishouEticketStableInfo(payload = {}) {
}) })
} }
export function mapKuaishouEticketStableInfoResult(payload = {}, context = {}) { export function mapKuaishouEticketStableInfoResult(payload: JsonObject = {}, context: JsonObject = {}) {
const result = Number(payload?.result || 0) const result = Number(payload?.result || 0)
const userInfo = isPlainObject(payload?.data?.userInfo) ? payload.data.userInfo : {} const userInfo = isPlainObject(payload?.data?.userInfo) ? payload.data.userInfo : {}
const bizStatus = isPlainObject(payload?.data?.bizStatus) ? payload.data.bizStatus : {} const bizStatus = isPlainObject(payload?.data?.bizStatus) ? payload.data.bizStatus : {}
@@ -51,11 +51,11 @@ export function mapKuaishouEticketStableInfoResult(payload = {}, context = {}) {
} }
} }
function normalizeInteger(value, fallback) { function normalizeInteger(value: unknown, fallback: number): number {
const parsed = Number(value) const parsed = Number(value)
return Number.isInteger(parsed) ? parsed : fallback return Number.isInteger(parsed) ? parsed : fallback
} }
function isPlainObject(value) { function isPlainObject(value: unknown): value is JsonObject {
return Object.prototype.toString.call(value) === '[object Object]' return Object.prototype.toString.call(value) === '[object Object]'
} }
@@ -1,10 +1,41 @@
// @ts-check
const DEFAULT_BASE_URL = 'https://s.kwaixiaodian.com' const DEFAULT_BASE_URL = 'https://s.kwaixiaodian.com'
const DEFAULT_REFERER_PATH = '/zone/industry/voucher/verify-list' const DEFAULT_REFERER_PATH = '/zone/industry/voucher/verify-list'
const DEFAULT_USER_AGENT = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/147.0.0.0 Safari/537.36' const DEFAULT_USER_AGENT = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/147.0.0.0 Safari/537.36'
export function resolveKuaishouEticketConfig(overrides = {}) { export type KuaishouEticketConfigInput = {
enabled?: boolean
baseUrl?: string
cookie?: string
timeoutMs?: number | string
infoPath?: string
detailPath?: string
consumePath?: string
refererPath?: string
userAgent?: string
}
export type KuaishouEticketConfig = {
enabled: boolean
baseUrl: string
cookie: string
timeoutMs: number
infoPath: string
detailPath: string
consumePath: string
refererPath: string
userAgent: string
}
type HeaderInput = {
baseUrl?: string
refererPath?: string
userAgent?: string
cookie?: string
contentType?: string
extra?: Record<string, unknown>
}
export function resolveKuaishouEticketConfig(overrides: KuaishouEticketConfigInput = {}): KuaishouEticketConfig {
return { return {
enabled: overrides.enabled !== false, enabled: overrides.enabled !== false,
baseUrl: normalizeBaseUrl(overrides.baseUrl || DEFAULT_BASE_URL) || DEFAULT_BASE_URL, baseUrl: normalizeBaseUrl(overrides.baseUrl || DEFAULT_BASE_URL) || DEFAULT_BASE_URL,
@@ -18,7 +49,7 @@ export function resolveKuaishouEticketConfig(overrides = {}) {
} }
} }
export function buildKuaishouEticketUrl(baseUrl, pathname) { export function buildKuaishouEticketUrl(baseUrl: unknown, pathname: unknown): URL {
return new URL(normalizePath(pathname, '/'), normalizeBaseUrl(baseUrl) || DEFAULT_BASE_URL) return new URL(normalizePath(pathname, '/'), normalizeBaseUrl(baseUrl) || DEFAULT_BASE_URL)
} }
@@ -29,7 +60,7 @@ export function buildKuaishouEticketHeaders({
cookie = '', cookie = '',
contentType = 'application/json', contentType = 'application/json',
extra = {}, extra = {},
} = {}) { }: HeaderInput = {}): Record<string, string> {
return { return {
accept: 'application/json', accept: 'application/json',
'accept-language': 'zh-CN,zh;q=0.9', 'accept-language': 'zh-CN,zh;q=0.9',
@@ -44,11 +75,11 @@ export function buildKuaishouEticketHeaders({
} }
} }
function normalizeBaseUrl(value) { function normalizeBaseUrl(value: unknown): string {
return String(value || '').trim().replace(/\/+$/, '') return String(value || '').trim().replace(/\/+$/, '')
} }
function normalizePath(value, fallback) { function normalizePath(value: unknown, fallback: string): string {
const normalized = String(value || '').trim() const normalized = String(value || '').trim()
if (!normalized) { if (!normalized) {
return fallback return fallback
@@ -57,12 +88,12 @@ function normalizePath(value, fallback) {
return normalized.startsWith('/') ? normalized : `/${normalized}` return normalized.startsWith('/') ? normalized : `/${normalized}`
} }
function normalizePositiveInteger(value, fallback) { function normalizePositiveInteger(value: unknown, fallback: number): number {
const parsed = Number(value) const parsed = Number(value)
return Number.isInteger(parsed) && parsed > 0 ? parsed : fallback return Number.isInteger(parsed) && parsed > 0 ? parsed : fallback
} }
function normalizeHeaderMap(extra) { function normalizeHeaderMap(extra: unknown): Record<string, string> {
if (!extra || typeof extra !== 'object') { if (!extra || typeof extra !== 'object') {
return {} return {}
} }
@@ -1,5 +1,3 @@
// @ts-check
import fs from 'node:fs' import fs from 'node:fs'
import path from 'node:path' import path from 'node:path'
@@ -8,26 +6,42 @@ import { PROJECT_ROOT } from '../../../config/runtime.js'
const KUAISHOU_ETICKET_SOURCE_FILE_PATH = path.join(PROJECT_ROOT, 'data', 'kuaishou-eticket-source.json') const KUAISHOU_ETICKET_SOURCE_FILE_PATH = path.join(PROJECT_ROOT, 'data', 'kuaishou-eticket-source.json')
const DEFAULT_BASE_URL = 'https://s.kwaixiaodian.com' const DEFAULT_BASE_URL = 'https://s.kwaixiaodian.com'
export function getKuaishouEticketSourceFilePath() { type JsonObject = Record<string, any>
export type KuaishouEticketShopConfig = {
shopId: string
kshopName: string
cookie: string
userAvatar: string
enabled: boolean
}
export type KuaishouEticketSourceConfig = {
enabled: boolean
baseUrl: string
shops: KuaishouEticketShopConfig[]
}
export function getKuaishouEticketSourceFilePath(): string {
return KUAISHOU_ETICKET_SOURCE_FILE_PATH return KUAISHOU_ETICKET_SOURCE_FILE_PATH
} }
export function getKuaishouEticketSourceConfig() { export function getKuaishouEticketSourceConfig(): KuaishouEticketSourceConfig {
return loadKuaishouEticketSourceConfigFromFile() return loadKuaishouEticketSourceConfigFromFile()
} }
export function saveKuaishouEticketSourceConfig(rawValue) { export function saveKuaishouEticketSourceConfig(rawValue: unknown): KuaishouEticketSourceConfig {
const normalized = normalizeKuaishouEticketSourceConfig(rawValue) const normalized = normalizeKuaishouEticketSourceConfig(rawValue)
fs.mkdirSync(path.dirname(KUAISHOU_ETICKET_SOURCE_FILE_PATH), { recursive: true }) fs.mkdirSync(path.dirname(KUAISHOU_ETICKET_SOURCE_FILE_PATH), { recursive: true })
fs.writeFileSync(KUAISHOU_ETICKET_SOURCE_FILE_PATH, `${JSON.stringify(normalized, null, 2)}\n`, 'utf8') fs.writeFileSync(KUAISHOU_ETICKET_SOURCE_FILE_PATH, `${JSON.stringify(normalized, null, 2)}\n`, 'utf8')
return normalized return normalized
} }
export function listKuaishouEticketShopConfigs(source = getKuaishouEticketSourceConfig()) { export function listKuaishouEticketShopConfigs(source: KuaishouEticketSourceConfig = getKuaishouEticketSourceConfig()): KuaishouEticketShopConfig[] {
return Array.isArray(source?.shops) ? source.shops : [] return Array.isArray(source?.shops) ? source.shops : []
} }
export function findKuaishouEticketShopConfig(shopId, source = getKuaishouEticketSourceConfig()) { export function findKuaishouEticketShopConfig(shopId: unknown, source: KuaishouEticketSourceConfig = getKuaishouEticketSourceConfig()): KuaishouEticketShopConfig | null {
const normalizedShopId = String(shopId || '').trim() const normalizedShopId = String(shopId || '').trim()
if (!normalizedShopId) { if (!normalizedShopId) {
return null return null
@@ -36,7 +50,7 @@ export function findKuaishouEticketShopConfig(shopId, source = getKuaishouEticke
return listKuaishouEticketShopConfigs(source).find((item) => String(item.shopId || '').trim() === normalizedShopId) || null return listKuaishouEticketShopConfigs(source).find((item) => String(item.shopId || '').trim() === normalizedShopId) || null
} }
export function findKuaishouEticketShopConfigByName(kshopName, source = getKuaishouEticketSourceConfig()) { export function findKuaishouEticketShopConfigByName(kshopName: unknown, source: KuaishouEticketSourceConfig = getKuaishouEticketSourceConfig()): KuaishouEticketShopConfig | null {
const normalizedName = String(kshopName || '').trim() const normalizedName = String(kshopName || '').trim()
if (!normalizedName) { if (!normalizedName) {
return null return null
@@ -46,9 +60,9 @@ export function findKuaishouEticketShopConfigByName(kshopName, source = getKuais
} }
export function resolveKuaishouEticketShopConfig( export function resolveKuaishouEticketShopConfig(
{ shopId = '', kshopName = '', shopName = '' } = {}, { shopId = '', kshopName = '', shopName = '' }: { shopId?: unknown, kshopName?: unknown, shopName?: unknown } = {},
source = getKuaishouEticketSourceConfig(), source: KuaishouEticketSourceConfig = getKuaishouEticketSourceConfig(),
) { ): KuaishouEticketShopConfig | null {
const byId = findKuaishouEticketShopConfig(shopId, source) const byId = findKuaishouEticketShopConfig(shopId, source)
if (byId) { if (byId) {
return byId return byId
@@ -62,11 +76,11 @@ export function resolveKuaishouEticketShopConfig(
return findKuaishouEticketShopConfigByName(normalizedName, source) return findKuaishouEticketShopConfigByName(normalizedName, source)
} }
export function getFirstAvailableKuaishouEticketShop(source = getKuaishouEticketSourceConfig()) { export function getFirstAvailableKuaishouEticketShop(source: KuaishouEticketSourceConfig = getKuaishouEticketSourceConfig()): KuaishouEticketShopConfig | null {
return listKuaishouEticketShopConfigs(source).find((item) => item.enabled !== false && String(item.cookie || '').trim()) || null return listKuaishouEticketShopConfigs(source).find((item) => item.enabled !== false && String(item.cookie || '').trim()) || null
} }
function loadKuaishouEticketSourceConfigFromFile() { function loadKuaishouEticketSourceConfigFromFile(): KuaishouEticketSourceConfig {
if (!fs.existsSync(KUAISHOU_ETICKET_SOURCE_FILE_PATH)) { if (!fs.existsSync(KUAISHOU_ETICKET_SOURCE_FILE_PATH)) {
return createDefaultKuaishouEticketSourceConfig() return createDefaultKuaishouEticketSourceConfig()
} }
@@ -79,7 +93,7 @@ function loadKuaishouEticketSourceConfigFromFile() {
} }
} }
function normalizeKuaishouEticketSourceConfig(rawValue) { function normalizeKuaishouEticketSourceConfig(rawValue: unknown): KuaishouEticketSourceConfig {
const source = isPlainObject(rawValue) ? rawValue : {} const source = isPlainObject(rawValue) ? rawValue : {}
const shops = Array.isArray(source.shops) const shops = Array.isArray(source.shops)
? source.shops ? source.shops
@@ -94,7 +108,7 @@ function normalizeKuaishouEticketSourceConfig(rawValue) {
} }
} }
function normalizeKuaishouEticketShopConfig(rawValue) { function normalizeKuaishouEticketShopConfig(rawValue: unknown): KuaishouEticketShopConfig | null {
if (!isPlainObject(rawValue)) { if (!isPlainObject(rawValue)) {
return null return null
} }
@@ -118,7 +132,7 @@ function normalizeKuaishouEticketShopConfig(rawValue) {
} }
} }
function buildLegacySingleShopList(source) { function buildLegacySingleShopList(source: JsonObject): JsonObject[] {
const cookie = String(source.cookie || '').trim() const cookie = String(source.cookie || '').trim()
if (!cookie) { if (!cookie) {
return [] return []
@@ -135,7 +149,7 @@ function buildLegacySingleShopList(source) {
] ]
} }
function createDefaultKuaishouEticketSourceConfig() { function createDefaultKuaishouEticketSourceConfig(): KuaishouEticketSourceConfig {
return { return {
enabled: true, enabled: true,
baseUrl: DEFAULT_BASE_URL, baseUrl: DEFAULT_BASE_URL,
@@ -143,6 +157,6 @@ function createDefaultKuaishouEticketSourceConfig() {
} }
} }
function isPlainObject(value) { function isPlainObject(value: unknown): value is JsonObject {
return Object.prototype.toString.call(value) === '[object Object]' return Object.prototype.toString.call(value) === '[object Object]'
} }
+13
View File
@@ -795,6 +795,19 @@
- `npm run build` - `npm run build`
- `npm test` 共 139 个用例通过 - `npm test` 共 139 个用例通过
204. `src/services/admin` 目录下非测试 `.js` 服务文件已全部迁移为 `.ts` 204. `src/services/admin` 目录下非测试 `.js` 服务文件已全部迁移为 `.ts`
205. 快手电子券平台服务迁移到 `.ts`
- `src/services/platforms/kuaishou-eticket/shared.ts`
- `src/services/platforms/kuaishou-eticket/http-client.ts`
- `src/services/platforms/kuaishou-eticket/source-config-service.ts`
- `src/services/platforms/kuaishou-eticket/info-service.ts`
- `src/services/platforms/kuaishou-eticket/consume-service.ts`
206. 快手小店核销配置、Node HTTP 请求、店铺来源配置读写、店铺稳定信息查询、电子券详情查询与核销 payload / result 映射已进入 TS 编译链路;config、headers、HTTP response、source/shop config、detail result 与动态 payload 补齐类型
207. Docker 内验证通过:
- `src/services/platforms/kuaishou-eticket/*.test.js` 共 4 个用例通过
- `npm run typecheck`
- `npm run build`
- `npm test` 共 139 个用例通过
208. `src/services` 目录下非测试 `.js` 服务文件已全部迁移为 `.ts`
## 下一步建议 ## 下一步建议