收紧后端 TypeScript:统一 Json 类型与 TaskContext 契约

关闭 allowJs;集中 JsonObject 定义并替换分散 any 别名;parseTaskContext 返回 TaskContext;任务详情 API 标注 AdminTaskDetailView;测试减少 as any。
This commit is contained in:
yml2213
2026-07-10 15:52:05 +08:00
parent e7244eaa5e
commit 8bcd9bbd81
79 changed files with 415 additions and 259 deletions
@@ -1,8 +1,7 @@
import { createHttpError, type HttpErrorLike } from '../../../utils/http.js'
import { cloudtentaclesRequest } from './http-client.js'
import { resolveCloudtentaclesConfig } from './helpers.js'
type JsonObject = Record<string, any>
import type { JsonObject } from '../../../types/json.js'
export async function getCloudtentaclesAsset(payload: JsonObject = {}) {
const token = requireToken(payload.token, 'cloudtentacles 余额查询缺少 token', 'cloudtentacles_asset_missing_token')
@@ -1,10 +1,9 @@
import { createHash, constants, publicEncrypt } from 'node:crypto'
import type { JsonObject } from '../../../types/json.js'
import { createHttpError } from '../../../utils/http.js'
import { resolveCloudtentaclesConfig } from './helpers.js'
type JsonObject = Record<string, any>
export function md5CloudtentaclesPassword(password: unknown) {
return createHash('md5').update(String(password || ''), 'utf8').digest('hex')
}
@@ -1,6 +1,7 @@
import { createHttpError } from '../../../utils/http.js'
import { getCloudtentaclesAsset, listCloudtentaclesSku, buyCloudtentaclesSku } from './catalog-service.js'
import { getCloudtentaclesKnapsack } from './knapsack-service.js'
import type { JsonObject } from '../../../types/json.js'
import {
appointCloudtentaclesVirtualNumber,
fetchCloudtentaclesVirtualNumberCode,
@@ -9,7 +10,6 @@ import {
verifyCloudtentaclesLoginCode,
} from './virtual-number-service.js'
type JsonObject = Record<string, any>
type FlowStepOptions = {
retries?: number
retryDelayMs?: number
@@ -1,4 +1,5 @@
import { runtimeConfig } from '../../../config/runtime.js'
import type { JsonObject } from '../../../types/json.js'
import type { RuntimeConfig } from '../../../types/runtime-config.js'
import {
@@ -9,8 +10,6 @@ import {
} from './defaults.js'
type CloudtentaclesRuntimeConfig = RuntimeConfig['platforms']['cloudtentacles']
type JsonObject = Record<string, any>
export function resolveCloudtentaclesConfig(overrides: Partial<CloudtentaclesRuntimeConfig> = {}) {
const baseConfig = runtimeConfig.platforms?.cloudtentacles || {
baseUrl: '',
@@ -1,12 +1,12 @@
import http from 'node:http'
import https from 'node:https'
import type { JsonObject } from '../../../types/json.js'
import { createHttpError } from '../../../utils/http.js'
import { logInfo, logWarn } from '../../../utils/logger.js'
import { notifyCloudtentaclesAuthExpired } from '../../notification/domain-notifications.js'
import { buildCloudtentaclesHeaders, buildCloudtentaclesUrl, resolveCloudtentaclesConfig } from './helpers.js'
type JsonObject = Record<string, any>
type HeaderAdapter = {
get(name: unknown): string | null
}
@@ -1,8 +1,7 @@
import { createHttpError } from '../../../utils/http.js'
import { cloudtentaclesRequest } from './http-client.js'
import { resolveCloudtentaclesConfig } from './helpers.js'
type JsonObject = Record<string, any>
import type { JsonObject } from '../../../types/json.js'
export async function getCloudtentaclesKnapsack(payload: JsonObject = {}) {
const token = String(payload.token || '').trim()
@@ -2,8 +2,7 @@ import { createHttpError } from '../../../utils/http.js'
import { logInfo } from '../../../utils/logger.js'
import { cloudtentaclesRequest } from './http-client.js'
import { resolveCloudtentaclesConfig } from './helpers.js'
type JsonObject = Record<string, any>
import type { JsonObject } from '../../../types/json.js'
export type CloudtentaclesDeliveryRecordQuery = JsonObject & {
baseUrl?: string
@@ -3,8 +3,7 @@ import { logInfo } from '../../../utils/logger.js'
import { encryptCloudtentaclesPayload, md5CloudtentaclesPassword } from './crypto-service.js'
import { cloudtentaclesRequest } from './http-client.js'
import { resolveCloudtentaclesConfig } from './helpers.js'
type JsonObject = Record<string, any>
import type { JsonObject } from '../../../types/json.js'
export async function sendCloudtentaclesSmsCode(payload: JsonObject = {}) {
const username = String(payload.username || '').trim()
@@ -1,4 +1,5 @@
import path from 'node:path'
import type { JsonObject } from '../../../types/json.js'
import { APP_CONFIG_KEYS } from '../../../config/app-config-keys.js'
import { PROJECT_ROOT } from '../../../config/runtime.js'
@@ -16,7 +17,6 @@ import {
const CLOUDTENTACLES_SESSION_FILE_PATH = path.join(PROJECT_ROOT, 'data', 'cloudtentacles-session.json')
type JsonObject = Record<string, any>
type CloudtentaclesSessionState = ReturnType<typeof createDefaultCloudtentaclesSessionState>
type CloudtentaclesSessionStatesFile = {
sessions: Record<string, CloudtentaclesSessionState>
@@ -1,4 +1,5 @@
import path from 'node:path'
import type { JsonObject } from '../../../types/json.js'
import { APP_CONFIG_KEYS } from '../../../config/app-config-keys.js'
import { PROJECT_ROOT } from '../../../config/runtime.js'
@@ -14,8 +15,6 @@ import {
const CLOUDTENTACLES_SOURCES_FILE_PATH = path.join(PROJECT_ROOT, 'data', 'cloudtentacles-sources.json')
type JsonObject = Record<string, any>
export function getCloudtentaclesSourcesFilePath() {
return CLOUDTENTACLES_SOURCES_FILE_PATH
}
@@ -1,5 +1,6 @@
import http from 'node:http'
import https from 'node:https'
import type { JsonObject } from '../../../types/json.js'
import { createHttpError } from '../../../utils/http.js'
import { cloudtentaclesRequest } from './http-client.js'
@@ -8,7 +9,6 @@ import { resolveCloudtentaclesConfig } from './helpers.js'
const BIND_URL_PROBE_MAX_BODY_BYTES = 64 * 1024
const AMS_SIGNATURE_EXPIRED_CODE = '99998'
type JsonObject = Record<string, any>
type HeaderAdapter = {
get(name: unknown): string | null
}
@@ -1,11 +1,10 @@
import crypto from 'node:crypto'
import { asJsonObject, type JsonObject } from '../../../types/json.js'
import { createHttpError } from '../../../utils/http.js'
import { createRequestId, logExternalHttpPacket } from '../../../utils/logger.js'
import { assertKuaishouFeifeiConfig } from './config.js'
type JsonObject = Record<string, any>
export async function kuaishouFeifeiRequest(pathname: string, payload: JsonObject = {}) {
const config = assertKuaishouFeifeiConfig()
const body = JSON.stringify(payload)
@@ -189,7 +188,7 @@ export function isKuaishouFeifeiSuccessResponse(json: JsonObject) {
function parseJsonObject(text: string): JsonObject {
try {
const parsed = JSON.parse(text || '{}')
return parsed && typeof parsed === 'object' && !Array.isArray(parsed) ? parsed : {}
return asJsonObject(parsed)
} catch {
return {}
}
@@ -1,4 +1,5 @@
import crypto from 'node:crypto'
import type { JsonObject } from '../../../types/json.js'
import { createTaskEvent } from '../../../repositories/task-event-repo.js'
import { findKuaishouFeifeiTaskByOrder } from '../../../repositories/task-repo.js'
@@ -9,7 +10,6 @@ import { assertKuaishouFeifeiConfig } from './config.js'
import { signKuaishouFeifeiPayload } from './http-client.js'
import { mapKuaishouFeifeiOrder } from './order-service.js'
type JsonObject = Record<string, any>
type NotifyHeaders = Record<string, string | string[] | undefined>
export async function handleKuaishouFeifeiNotify(input: {
@@ -1,7 +1,6 @@
import { getKuaishouFeifeiConfig } from './config.js'
import { kuaishouFeifeiRequest } from './http-client.js'
type JsonObject = Record<string, any>
import type { JsonObject } from '../../../types/json.js'
export type KuaishouFeifeiProductListResult = ReturnType<typeof mapKuaishouFeifeiProductList>
@@ -1,4 +1,5 @@
import path from 'node:path'
import type { JsonObject } from '../../../types/json.js'
import { APP_CONFIG_KEYS } from '../../../config/app-config-keys.js'
import { PROJECT_ROOT } from '../../../config/runtime.js'
@@ -16,8 +17,6 @@ const KUAISHOU_FEIFEI_CONFIG_FILE_PATH = path.join(
'kuaishou-feifei-config.json',
)
type JsonObject = Record<string, any>
export type KuaishouFeifeiSourceConfig = {
enabled: boolean
baseUrl: string
@@ -3,6 +3,7 @@ import { findKuaishouIndustryVoucherByCode } from '../../../repositories/kuaisho
import { normalizeTimestampIso } from '../../../utils/time.js'
import { logWarn } from '../../../utils/logger.js'
import { TASK_STATUS } from '../../../domain/task-status.js'
import type { JsonObject } from '../../../types/json.js'
import {
getKuaishouIndustryConfig,
assertMatchingAppKey,
@@ -17,8 +18,6 @@ import { consumeCallback } from './consume-callback-service.js'
import { consumeKuaishouIndustryVoucher } from './voucher-service.js'
import { attachKuaishouIndustryVoucherToTask } from './voucher-binding-service.js'
type JsonObject = Record<string, any>
export async function handleConsumeCode(rawBody: JsonObject = {}) {
const config = getKuaishouIndustryConfig()
@@ -1,11 +1,10 @@
import crypto from 'node:crypto'
import type { JsonObject } from '../../../types/json.js'
import { createHttpError } from '../../../utils/http.js'
import { logWarn } from '../../../utils/logger.js'
import { assertKuaishouIndustryConfig } from './config.js'
type JsonObject = Record<string, any>
export type SignMethod = 'MD5' | 'HMAC_SHA256'
export function buildKuaishouIndustrySignSource(params: JsonObject = {}, { signSecret } = assertKuaishouIndustryConfig()) {
@@ -1,4 +1,5 @@
import { updateTask } from '../../../repositories/task-repo.js'
import type { JsonObject } from '../../../types/json.js'
import {
listKuaishouIndustryVouchersByOid,
updateKuaishouIndustryVoucherByCode,
@@ -18,8 +19,6 @@ import {
import { destroyCallback } from './destroy-callback-service.js'
import { attachKuaishouIndustryVoucherToTask } from './voucher-binding-service.js'
type JsonObject = Record<string, any>
export async function handleDestroyCode(rawBody: JsonObject = {}) {
const config = getKuaishouIndustryConfig()
@@ -2,8 +2,8 @@ import { getKuaishouIndustryConfig } from './config.js'
import { signKuaishouIndustryPayload, type SignMethod } from './crypto.js'
import { ensureKuaishouIndustryAccessToken } from './token-service.js'
import { logIntegration } from '../../../utils/logger.js'
export type JsonObject = Record<string, any>
import type { JsonObject } from '../../../types/json.js'
export type { JsonObject }
type KuaishouIndustryOpenApiCallInput = {
apiMethod: string
@@ -1,5 +1,5 @@
export type JsonObject = Record<string, any>
import type { JsonObject } from '../../../types/json.js'
export type { JsonObject }
export function pickDefinedBizParams(input: JsonObject): JsonObject {
const output: JsonObject = {}
@@ -1,7 +1,6 @@
import { createHttpError } from '../../../utils/http.js'
import { assertKuaishouIndustryConfig } from './config.js'
type JsonObject = Record<string, any>
import { asJsonObject, type JsonObject } from '../../../types/json.js'
export function normalizeIndustryString(value: unknown) {
return String(value || '').trim()
@@ -239,7 +238,7 @@ function parseParamField(raw: JsonObject) {
try {
const parsed = JSON.parse(normalizeIndustryString(raw.param || '{}'))
return parsed && typeof parsed === 'object' && !Array.isArray(parsed) ? parsed : {}
return asJsonObject(parsed)
} catch {
return {}
}
@@ -1,3 +1,4 @@
import type { JsonObject } from '../../../types/json.js'
import {
findKuaishouIndustryVoucherByCode,
listKuaishouIndustryVouchersByOid,
@@ -18,8 +19,6 @@ import {
isKuaishouIndustryVoucherSendCallbackSuccess,
} from './voucher-service.js'
type JsonObject = Record<string, any>
export async function handleQueryCode(rawBody: JsonObject = {}) {
const config = getKuaishouIndustryConfig()
@@ -1,5 +1,4 @@
type JsonObject = Record<string, any>
import type { JsonObject } from '../../../types/json.js'
export function buildIndustrySuccessResponse(data: unknown = null) {
return {
result: 1,
@@ -1,5 +1,6 @@
import { findLatestOrderByPlatformOrderId } from '../../../repositories/order-repo.js'
import { listTasksByOrderId } from '../../../repositories/task-repo.js'
import { asJsonObject, type JsonObject } from '../../../types/json.js'
import {
findKuaishouIndustryVoucherByCode,
listKuaishouIndustryVouchersByOid,
@@ -33,8 +34,6 @@ import { bindKuaishouIndustryVouchersToOrderTasks } from './voucher-binding-serv
import { parseAmountToFen } from '../../../utils/money.js'
import type { KuaishouIndustryVoucherRow, OrderRow } from '../../../types/repository/rows.js'
type JsonObject = Record<string, any>
type SendCodeCallbackParams = {
oid: string
sendType: string
@@ -677,7 +676,7 @@ function parseJsonObject(value: unknown): JsonObject {
try {
const parsed = JSON.parse(String(value || '{}'))
return parsed && typeof parsed === 'object' && !Array.isArray(parsed) ? parsed : {}
return asJsonObject(parsed)
} catch {
return {}
}
@@ -1,4 +1,5 @@
import path from 'node:path'
import type { JsonObject } from '../../../types/json.js'
import { APP_CONFIG_KEYS } from '../../../config/app-config-keys.js'
import { PROJECT_ROOT, runtimeConfig } from '../../../config/runtime.js'
@@ -14,8 +15,6 @@ const LEGACY_DEFAULT_REDIRECT_URI = 'https://ks.khhao.com/oauth-callback'
const DEFAULT_REDIRECT_URI = 'https://ks.khhao.com/admin/platform-shops?tab=kuaishouIndustry'
const DEFAULT_SCOPES = 'merchant_item'
type JsonObject = Record<string, any>
export type KuaishouIndustryShopConfig = {
enabled: boolean
sellerId: string
@@ -1,5 +1,6 @@
import { createHttpError } from '../../../utils/http.js'
import { logInfo, logWarn } from '../../../utils/logger.js'
import type { JsonObject } from '../../../types/json.js'
import {
findKuaishouIndustryShopConfig,
getKuaishouIndustrySourceConfig,
@@ -10,8 +11,6 @@ import {
type KuaishouIndustrySourceConfig,
} from './source-config-service.js'
type JsonObject = Record<string, any>
const ACCESS_TOKEN_REFRESH_MARGIN_MS = 30 * 60 * 1000
const DEFAULT_ACCESS_TOKEN_TTL_MS = 47 * 60 * 60 * 1000
const DEFAULT_REFRESH_TOKEN_TTL_MS = 179 * 24 * 60 * 60 * 1000
@@ -1,4 +1,5 @@
import { updateTask } from '../../../repositories/task-repo.js'
import type { JsonObject } from '../../../types/json.js'
import {
listKuaishouIndustryVouchersByOid,
updateKuaishouIndustryVoucherByCode,
@@ -17,8 +18,6 @@ import type {
TaskRow,
} from '../../../types/repository/rows.js'
type JsonObject = Record<string, any>
export async function bindKuaishouIndustryVouchersToOrderTasks(
order: OrderRow | null | undefined,
tasks: TaskRow[] = [],
@@ -1,4 +1,5 @@
import { createTaskEvent } from '../../../repositories/task-event-repo.js'
import { asJsonObject, type JsonObject } from '../../../types/json.js'
import {
findKuaishouIndustryVoucherByCode,
listKuaishouIndustryVouchersByTaskId,
@@ -9,8 +10,6 @@ import { buildIndustryEticketItem } from './response.js'
import { consumeCallback } from './consume-callback-service.js'
import type { KuaishouIndustryVoucherRow, TaskRow } from '../../../types/repository/rows.js'
type JsonObject = Record<string, any>
export const KUAISHOU_INDUSTRY_DEFAULT_VALID_DAYS = 3
export const KUAISHOU_INDUSTRY_SEND_CALLBACK_STATUS = {
PENDING: 'pending',
@@ -358,7 +357,7 @@ function parseJsonObject(value: unknown): JsonObject {
try {
const parsed = JSON.parse(String(value || '{}'))
return parsed && typeof parsed === 'object' && !Array.isArray(parsed) ? parsed : {}
return asJsonObject(parsed)
} catch {
return {}
}
@@ -4,6 +4,7 @@ import { listOrderItemsByOrderId, replaceOrderItems } from '../../../repositorie
import { listTasksByOrderId } from '../../../repositories/task-repo.js'
import { upsertOrderFromSource } from '../../order/order-service.js'
import { bindKuaishouIndustryVouchersToOrderTasks } from '../kuaishou-industry/voucher-binding-service.js'
import { asJsonObject, type JsonObject } from '../../../types/json.js'
import {
OPEN_91_PLATFORM,
OPEN_91_PROVIDER,
@@ -18,8 +19,6 @@ import type { OrderItemRow, OrderRow } from '../../../types/repository/rows.js'
export const OPEN_91_PENDING_CONFIG_STATUS = 'pending_config'
export const OPEN_91_MANUAL_FAILED_STATUS = 'manual_failed'
type JsonObject = Record<string, any>
export function buildOpen91SourceEvent(payload: JsonObject = {}, config: JsonObject = {}) {
const normalized = normalizeOpen91CreatePayload(payload)
const productInfo = parseOpen91ProductNo(normalized.productNo)
@@ -397,7 +396,7 @@ function parseJsonObject(value: unknown): JsonObject {
try {
const parsed = JSON.parse(String(value || '{}'))
return parsed && typeof parsed === 'object' && !Array.isArray(parsed) ? parsed : {}
return asJsonObject(parsed)
} catch {
return {}
}