收紧后端 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 { createAdminAuditLog, listAdminAuditLogs } from '../../repositories/admin-audit-log-repo.js'
import { nowIso } from '../../utils/time.js'
import { normalizeDateQuery, normalizePage, normalizePageSize, safeParseJson } from './admin-query-utils.js'
type JsonObject = Record<string, any>
import type { JsonObject } from '../../types/json.js'
export async function writeAdminAuditLog(session: JsonObject | null | undefined, payload: JsonObject = {}) {
if (!session?.userId) {
@@ -1,4 +1,5 @@
import crypto from 'node:crypto'
import type { JsonObject } from '../../types/json.js'
import { runtimeConfig } from '../../config/runtime.js'
import {
@@ -15,8 +16,6 @@ import { normalizePage, normalizePageSize } from './admin-query-utils.js'
type AdminUserRow = NonNullable<Awaited<ReturnType<typeof getAdminUserById>>>
type JsonObject = Record<string, any>
export type AdminSession = {
sessionId: string
userId: number
@@ -1,8 +1,7 @@
import { query } from '../../db/client.js'
import { TASK_STATUS } from '../../domain/task-status.js'
import { nowIso } from '../../utils/time.js'
type JsonObject = Record<string, any>
import type { JsonObject } from '../../types/json.js'
export async function getAdminDashboardSummary() {
const todayPrefix = nowIso().slice(0, 10)
@@ -1,5 +1,4 @@
type JsonObject = Record<string, any>
import type { JsonObject } from '../../types/json.js'
export function normalizePage(rawValue: unknown) {
const parsed = Number(rawValue)
return Number.isFinite(parsed) && parsed > 0 ? Math.floor(parsed) : 1
@@ -5,6 +5,7 @@ import { listOrderItemsByOrderId } from '../../repositories/order-item-repo.js'
import { getOrderById, listOrders } from '../../repositories/order-repo.js'
import { getTaskById, listTasks, listTasksByOrderId } from '../../repositories/task-repo.js'
import { listTaskEventsByTaskId } from '../../repositories/task-event-repo.js'
import type { JsonObject, JsonRecord } from '../../types/json.js'
import {
listKuaishouIndustryVouchersByOid,
listKuaishouIndustryVouchersByTaskId,
@@ -58,6 +59,7 @@ import type {
AdminOrderListResponse,
AdminTaskListResponse,
} from '../../types/admin/read-models.js'
import type { AdminTaskDetailView } from '../../types/admin/task-detail.js'
import type {
AdminEntityIdInput,
AdminOrderListQueryInput,
@@ -69,8 +71,6 @@ import type {
TaskRow,
} from '../../types/repository/rows.js'
type JsonRecord = Record<string, any>
export async function getAdminOrders(
query: AdminOrderListQueryInput = {},
): Promise<AdminOrderListResponse> {
@@ -218,7 +218,7 @@ export async function getAdminTasks(
export async function getAdminTaskDetail(
taskId: AdminEntityIdInput,
session: AdminViewerSessionInput | null = null,
): Promise<JsonRecord> {
): Promise<AdminTaskDetailView> {
const task = await getTaskById(Number(taskId))
if (!task) {
@@ -1,5 +1,6 @@
import { safeParseJson } from './admin-query-utils.js'
import { normalizeAdminRole } from './admin-auth-service.js'
import { asJsonObject, type JsonObject, JsonRecord } from '../../types/json.js'
import {
parseTaskContext as parseTaskContextValue,
parseTaskState as parseTaskStateValue,
@@ -9,7 +10,6 @@ import { canRegenerateClaimLinkStatus, isTaskFinalStatus } from '../../domain/ta
import type { AdminViewerSessionInput } from '../../types/admin/read-inputs.js'
import type { OrderItemRow, TaskRow } from '../../types/repository/rows.js'
type JsonRecord = Record<string, any>
type CloudSourceLabelMap = Map<string, string> | Record<string, string>
type KuaishouCloudFulfillmentMapOptions = {
@@ -74,14 +74,14 @@ export function mapKuaishouCloudFulfillmentContext(
}
const record = value as JsonRecord
const ticket = record.ticket && typeof record.ticket === 'object' ? record.ticket : {}
const binding = record.binding && typeof record.binding === 'object' ? record.binding : {}
const role = record.role && typeof record.role === 'object' ? record.role : {}
const purchase = record.purchase && typeof record.purchase === 'object' ? record.purchase : {}
const dispatch = record.dispatch && typeof record.dispatch === 'object' ? record.dispatch : {}
const ticket = asJsonObject(record.ticket)
const binding = asJsonObject(record.binding)
const role = asJsonObject(record.role)
const purchase = asJsonObject(record.purchase)
const dispatch = asJsonObject(record.dispatch)
const returnNumber =
record.returnNumber && typeof record.returnNumber === 'object' ? record.returnNumber : {}
const consume = record.consume && typeof record.consume === 'object' ? record.consume : {}
asJsonObject(record.returnNumber)
const consume = asJsonObject(record.consume)
const cloudSourceKeys = Array.isArray(binding.cloudSourceKeys)
? binding.cloudSourceKeys.map((value: unknown) => String(value || '').trim()).filter(Boolean)
: []
@@ -1,6 +1,7 @@
import { getTaskById } from '../../repositories/task-repo.js'
import { createHttpError } from '../../utils/http.js'
import { safeParseJson } from './admin-query-utils.js'
import { asJsonObject, type JsonObject, JsonRecord } from '../../types/json.js'
import {
TASK_STATUS,
isTaskFulfillmentCompletedStatus,
@@ -22,8 +23,6 @@ import type {
} from '../../types/repository/rows.js'
import type { AdminViewerContext } from './admin-read-shared-helpers.js'
type JsonRecord = Record<string, any>
type TaskFulfillmentState = {
resourceStatus: string
customerStatus: string
@@ -263,7 +262,7 @@ function isTaskFulfillmentCompleted(task: TaskRow | null | undefined): boolean {
}
function normalizeRecord(value: unknown): JsonRecord {
return value && typeof value === 'object' && !Array.isArray(value) ? value : {}
return asJsonObject(value)
}
function getTaskRetryCount(task: TaskRow | null | undefined): number {
@@ -1,3 +1,4 @@
import { asJsonObject, type JsonObject } from '../../types/json.js'
import {
findKuaishouIndustryVoucherByCode,
listKuaishouIndustryVouchersByOid,
@@ -27,8 +28,6 @@ import { reverseKuaishouIndustryCallback } from '../platforms/kuaishou-industry/
import type { KuaishouIndustryOpenApiCallResult } from '../platforms/kuaishou-industry/openapi-client.js'
import type { KuaishouIndustryVoucherRow, TaskRow } from '../../types/repository/rows.js'
type JsonObject = Record<string, any>
export async function listAdminKuaishouIndustryVouchers(
input: KuaishouIndustryVoucherAdminListQuery = {},
) {
@@ -462,7 +461,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,5 +1,3 @@
type JsonObject = Record<string, any>
export function pickFirstNonEmpty(values: unknown[]) {
for (const value of values) {
const normalized = String(value || "").trim();
@@ -17,6 +15,7 @@ export function isPlainObject(value: unknown): value is JsonObject {
import { getCloudtentaclesSourceByKey } from "../../../platforms/cloudtentacles/source-config-service.js";
import { getCloudtentaclesSessionStateByKey } from "../../../platforms/cloudtentacles/session-state-service.js";
import type { JsonObject } from '../../../../types/json.js'
import {
normalizeCloudtentaclesDeviceId,
normalizeCloudtentaclesDeviceType,
@@ -1,3 +1,4 @@
import type { JsonObject } from '../../../../types/json.js'
import {
getCloudtentaclesSourceByKey,
getCloudtentaclesSourcesFilePath,
@@ -79,8 +80,6 @@ import type {
AdminCloudtentaclesVirtualNumberInput,
} from "../../../../types/admin/write-inputs.js";
type JsonObject = Record<string, any>;
type LocalCloudtentaclesTask = {
taskId: number;
taskNo: string;
@@ -1,3 +1,4 @@
import type { JsonObject } from '../../../../types/json.js'
import {
maskPhone as maskPhoneValue,
maskSecret as maskSecretValue,
@@ -7,8 +8,6 @@ import {
normalizeCloudtentaclesDeviceType,
} from "../../../platforms/cloudtentacles/defaults.js";
type JsonObject = Record<string, any>
export function maskSecret(value: unknown) {
return maskSecretValue(value);
}
@@ -1,5 +1,6 @@
import { getCloudtentaclesSourceByKey } from "../../../platforms/cloudtentacles/source-config-service.js";
import { getCloudtentaclesSessionStateByKey } from "../../../platforms/cloudtentacles/session-state-service.js";
import type { JsonObject } from '../../../../types/json.js'
import {
normalizeCloudtentaclesDeviceId,
normalizeCloudtentaclesDeviceType,
@@ -12,8 +13,6 @@ import { maskPhone, maskSecret } from "./mappers.js";
const DEFAULT_CLOUDTENTACLES_BASE_URL = "https://123.207.217.176";
type JsonObject = Record<string, any>
function _resolveSourceKey(payload: JsonObject = {}) {
return String(payload.sourceKey || "").trim() || "default";
}
@@ -1,10 +1,9 @@
import type { JsonObject } from '../../../../types/json.js'
import {
normalizeCloudtentaclesDeviceId,
normalizeCloudtentaclesDeviceType,
} from "../../../platforms/cloudtentacles/defaults.js";
type JsonObject = Record<string, any>;
export function normalizeAdminCloudtentaclesSourceConfigPayload(
payload: JsonObject = {}
) {
@@ -1,4 +1,5 @@
import { getKuaishouFeifeiConfig } from '../../platforms/kuaishou-feifei/config.js'
import type { JsonObject } from '../../../types/json.js'
import {
createKuaishouFeifeiOrder,
listKuaishouFeifeiProducts,
@@ -16,8 +17,6 @@ import {
import { normalizeCloudtentaclesMatchName } from '../../order/cloudtentacles-match-utils.js'
import { createHttpError } from '../../../utils/http.js'
type JsonObject = Record<string, any>
export function getAdminKuaishouFeifeiConfig() {
const source = getAdminEditableKuaishouFeifeiConfig()
const effective = getKuaishouFeifeiConfig()
@@ -1,5 +1,6 @@
import { maskSecret } from '../../../utils/masking.js'
import { createHttpError } from '../../../utils/http.js'
import type { JsonObject } from '../../../types/json.js'
import {
findKuaishouIndustryShopConfig,
getKuaishouIndustrySourceConfig,
@@ -13,8 +14,6 @@ import {
refreshKuaishouIndustryAccessToken,
} from '../../platforms/kuaishou-industry/token-service.js'
type JsonObject = Record<string, any>
const SECRET_FIELDS = [
'appSecret',
'signSecret',
@@ -1,11 +1,10 @@
import type { JsonObject } from '../../../types/json.js'
import {
failOpen91Order,
listOpen91Orders,
retryOpen91Order,
} from '../../platforms/ninetyone/order-service.js'
type JsonObject = Record<string, any>
export async function getAdminNinetyoneOrders(query: JsonObject = {}) {
return listOpen91Orders({
page: Number(query.page || 1) || 1,
@@ -1,3 +1,4 @@
import type { JsonObject } from '../../../types/json.js'
import {
getNotificationConfig,
getNotificationConfigFilePath,
@@ -24,8 +25,6 @@ import type {
AdminScheduledJobsConfigInput,
} from '../../../types/admin/write-inputs.js'
type JsonObject = Record<string, any>
export function getAdminNotificationConfig() {
const config = getNotificationConfig()
@@ -1,6 +1,7 @@
import { getOrderById } from '../../../repositories/order-repo.js'
import { listTasksByOrderId, updateTask } from '../../../repositories/task-repo.js'
import { createTaskEvent } from '../../../repositories/task-event-repo.js'
import type { JsonObject } from '../../../types/json.js'
import {
findKuaishouIndustryVoucherByCode,
listKuaishouIndustryVouchersByOid,
@@ -670,9 +671,9 @@ async function getRequiredIndustryVoucherForTask(task: TaskRow): Promise<Kuaisho
})
}
function normalizeAdminTaskIndustryVoucherContext(value: unknown): Record<string, any> {
function normalizeAdminTaskIndustryVoucherContext(value: unknown): JsonObject {
return value && typeof value === 'object' && !Array.isArray(value)
? value as Record<string, any>
? value as JsonObject
: {}
}
@@ -1,8 +1,9 @@
import { createHttpError } from '../../../utils/http.js'
import type { HttpErrorLike } from '../../../utils/http.js'
import {
resolvePersistedCloudtentaclesContextBySourceKeys,
} from '../../fulfillment/kuaishou-cloud/cloudtentacles-context.js'
import type { JsonObject } from '../../../types/json.js'
import { resolvePersistedCloudtentaclesContextBySourceKeys } from '../../fulfillment/kuaishou-cloud/cloudtentacles-context.js'
export type { JsonObject }
export {
KUAISHOU_CLOUD_FIXED_VN_KEY,
@@ -10,7 +11,6 @@ export {
normalizeKuaishouCloudFlow,
normalizeKuaishouCloudRoleInfo,
resolveKuaishouCloudBindUrlExpiresAt,
type JsonObject,
} from '../../fulfillment/kuaishou-cloud/domain.js'
export {
prepareKuaishouCloudBindResourceWithFallback,
@@ -34,17 +34,17 @@ export type CloudSkuLikeItem = {
[key: string]: unknown
}
export type KuaishouCloudFlow = Record<string, any> & {
export type KuaishouCloudFlow = JsonObject & {
configId: string
internalSkuCode: string
internalSkuName: string
ticket: Record<string, any>
binding: Record<string, any>
role: Record<string, any>
purchase: Record<string, any>
dispatch: Record<string, any>
returnNumber: Record<string, any>
consume: Record<string, any>
ticket: JsonObject
binding: JsonObject
role: JsonObject
purchase: JsonObject
dispatch: JsonObject
returnNumber: JsonObject
consume: JsonObject
}
export type KuaishouCloudBindingResources = {