增强后端 TypeScript 严格类型检查

This commit is contained in:
yml2213
2026-05-26 10:07:19 +08:00
parent 6d9f267593
commit a2bce8b272
14 changed files with 66 additions and 31 deletions
+6 -1
View File
@@ -354,5 +354,10 @@ function setConfigValue(
current = current[key] as Record<string, unknown>; current = current[key] as Record<string, unknown>;
} }
current[configPath[configPath.length - 1]] = value; const lastKey = configPath[configPath.length - 1];
if (!lastKey) {
return;
}
current[lastKey] = value;
} }
+1 -1
View File
@@ -43,7 +43,7 @@ function resolveRequestId(req: Request): string {
} }
function shouldSkipAccessLog(originalUrl: string, statusCode: number): boolean { function shouldSkipAccessLog(originalUrl: string, statusCode: number): boolean {
const pathname = String(originalUrl || "").split("?")[0]; const pathname = String(originalUrl || "").split("?")[0] || "";
return ( return (
["/health", "/health/live", "/health/ready"].includes(pathname) && ["/health", "/health/live", "/health/ready"].includes(pathname) &&
Number(statusCode) < 400 Number(statusCode) < 400
@@ -109,6 +109,10 @@ export function resolveOrderItemSyncPlan(
if (matchedIndex >= 0) { if (matchedIndex >= 0) {
const matched = unmatchedExisting.splice(matchedIndex, 1)[0] const matched = unmatchedExisting.splice(matchedIndex, 1)[0]
if (!matched) {
creates.push(item)
continue
}
updates.push({ updates.push({
orderItemId: matched.id, orderItemId: matched.id,
item, item,
+13 -12
View File
@@ -195,18 +195,19 @@ export async function updateTask(taskId: number | string, patch: TaskUpdatePatch
) )
if (containsRuntimeContextPatch(patch)) { if (containsRuntimeContextPatch(patch)) {
await upsertTaskRuntimeContextWithClient(client, Number(taskId), { const runtimeContextPatch: TaskRuntimeContextPatch = {}
runtimeSessionId: patch.runtime_session_id, if (patch.runtime_session_id !== undefined) runtimeContextPatch.runtimeSessionId = patch.runtime_session_id
loginType: patch.login_type, if (patch.login_type !== undefined) runtimeContextPatch.loginType = patch.login_type
nickname: patch.nickname, if (patch.nickname !== undefined) runtimeContextPatch.nickname = patch.nickname
roleId: patch.role_id, if (patch.role_id !== undefined) runtimeContextPatch.roleId = patch.role_id
roleName: patch.role_name, if (patch.role_name !== undefined) runtimeContextPatch.roleName = patch.role_name
area: patch.area, if (patch.area !== undefined) runtimeContextPatch.area = patch.area
partitionName: patch.partition_name, if (patch.partition_name !== undefined) runtimeContextPatch.partitionName = patch.partition_name
screenshotPath: patch.screenshot_path, if (patch.screenshot_path !== undefined) runtimeContextPatch.screenshotPath = patch.screenshot_path
artifactsJson: patch.artifacts_json, if (patch.artifacts_json !== undefined) runtimeContextPatch.artifactsJson = patch.artifacts_json
stateJson: patch.state_json, if (patch.state_json !== undefined) runtimeContextPatch.stateJson = patch.state_json
}, patch.updated_at || current.updated_at)
await upsertTaskRuntimeContextWithClient(client, Number(taskId), runtimeContextPatch, patch.updated_at || current.updated_at)
} }
return getTaskByIdWithExecutor(client.query.bind(client) as TaskQueryExecutor, taskId) return getTaskByIdWithExecutor(client.query.bind(client) as TaskQueryExecutor, taskId)
+9 -1
View File
@@ -123,5 +123,13 @@ export function extractBearerToken(req: Request): string {
}) })
} }
return matched[1] const token = matched[1]?.trim()
if (!token) {
throw createHttpError('未登录或登录已失效', {
statusCode: 401,
errorCode: 'admin_auth_required',
})
}
return token
} }
+10 -2
View File
@@ -16,6 +16,14 @@ const open91RateLimit = createRateLimitMiddleware({
}, },
}) })
function resolveErrorStatusCode(error: unknown): number {
if (!error || typeof error !== 'object' || !('statusCode' in error)) {
return 500
}
return Number(error.statusCode || 500)
}
router.post('/orders/create', open91RateLimit, async (req, res) => { router.post('/orders/create', open91RateLimit, async (req, res) => {
const requestId = createRequestId('91') const requestId = createRequestId('91')
const startedAt = Date.now() const startedAt = Date.now()
@@ -38,7 +46,7 @@ router.post('/orders/create', open91RateLimit, async (req, res) => {
res.status(200).json(result) res.status(200).json(result)
} catch (error) { } catch (error) {
const message = error instanceof Error ? error.message : '系统错误' const message = error instanceof Error ? error.message : '系统错误'
const code = Number(error?.statusCode || 500) >= 500 ? 500 : 400 const code = resolveErrorStatusCode(error) >= 500 ? 500 : 400
logIntegration('[open-91/create]', '91卡券异步下单处理失败', { logIntegration('[open-91/create]', '91卡券异步下单处理失败', {
requestId, requestId,
durationMs: Date.now() - startedAt, durationMs: Date.now() - startedAt,
@@ -70,7 +78,7 @@ router.post('/orders/query', open91RateLimit, async (req, res) => {
res.status(200).json(result) res.status(200).json(result)
} catch (error) { } catch (error) {
const message = error instanceof Error ? error.message : '系统错误' const message = error instanceof Error ? error.message : '系统错误'
const code = Number(error?.statusCode || 500) >= 500 ? 500 : 400 const code = resolveErrorStatusCode(error) >= 500 ? 500 : 400
logIntegration('[open-91/query]', '91卡券订单查询处理失败', { logIntegration('[open-91/query]', '91卡券订单查询处理失败', {
requestId, requestId,
durationMs: Date.now() - startedAt, durationMs: Date.now() - startedAt,
@@ -26,9 +26,9 @@ export async function notifyInternalSafely(payload: InternalNotificationPayload)
try { try {
const result = await sendInternalNotification({ const result = await sendInternalNotification({
title: payload.title, title: payload.title,
body: payload.body, ...(payload.body !== undefined ? { body: payload.body } : {}),
category: payload.category, ...(payload.category !== undefined ? { category: payload.category } : {}),
url: payload.url, ...(payload.url !== undefined ? { url: payload.url } : {}),
}) })
markNotificationCooldown(cooldownKey) markNotificationCooldown(cooldownKey)
return result return result
@@ -40,12 +40,12 @@ export async function sendInternalNotification(input: NotificationInput = {}) {
...(await Promise.all(barkRecipients.map(async (recipient: JsonObject) => { ...(await Promise.all(barkRecipients.map(async (recipient: JsonObject) => {
try { try {
const result = await sendBarkNotification({ const result = await sendBarkNotification({
serverUrl: bark.serverUrl,
recipient, recipient,
title, title,
body, body,
group: `订单系统/${category}`, group: `订单系统/${category}`,
url: input.url, ...(bark.serverUrl !== undefined ? { serverUrl: bark.serverUrl } : {}),
...(input.url !== undefined ? { url: input.url } : {}),
}) })
return mapNotificationResult('bark', recipient, recipient.deviceKey, true, '', result.status, result.response) return mapNotificationResult('bark', recipient, recipient.deviceKey, true, '', result.status, result.response)
} catch (error) { } catch (error) {
@@ -115,8 +115,8 @@ export async function upsertOrderFromSource(
provider: event.provider, provider: event.provider,
platform: event.platform, platform: event.platform,
shopId: event.shopId, shopId: event.shopId,
shopIdAliases: event.shopIdAliases,
item, item,
...(event.shopIdAliases !== undefined ? { shopIdAliases: event.shopIdAliases } : {}),
})), })),
) )
const configuredItems = (resolvedItems as FulfillmentOrderItem[]).filter((item) => item.isConfigured) const configuredItems = (resolvedItems as FulfillmentOrderItem[]).filter((item) => item.isConfigured)
@@ -155,7 +155,7 @@ export async function upsertOrderFromSource(
totalAmount: event.totalAmount, totalAmount: event.totalAmount,
currency: event.currency, currency: event.currency,
rawPayloadJson: JSON.stringify(event.rawPayload), rawPayloadJson: JSON.stringify(event.rawPayload),
paidAt: event.paidAt, ...(event.paidAt !== undefined ? { paidAt: event.paidAt } : {}),
} }
const mergedPayload = mergeSourceOrderState(existing, basePayload) const mergedPayload = mergeSourceOrderState(existing, basePayload)
@@ -34,11 +34,12 @@ export async function cloudtentaclesRequest(pathname: unknown, options: JsonObje
}) })
try { try {
const body = normalizeRequestBody(options.body, headers['content-type'])
const response = await requestViaNodeHttp(url, { const response = await requestViaNodeHttp(url, {
method, method,
headers, headers,
body: normalizeRequestBody(options.body, headers['content-type']),
signal: controller.signal, signal: controller.signal,
...(body !== undefined ? { body } : {}),
}) })
const rawText = response.bodyText const rawText = response.bodyText
@@ -42,15 +42,16 @@ export async function kuaishouEticketRequest(pathname: string, options: Kuaishou
userAgent: config.userAgent, userAgent: config.userAgent,
cookie: options.cookie ?? config.cookie, cookie: options.cookie ?? config.cookie,
contentType: options.contentType === null ? '' : options.contentType || inferContentType(options.body), contentType: options.contentType === null ? '' : options.contentType || inferContentType(options.body),
extra: options.headers, ...(options.headers !== undefined ? { extra: options.headers } : {}),
}) })
try { try {
const body = normalizeRequestBody(options.body, headers['content-type'])
const response = await requestViaNodeHttp(url, { const response = await requestViaNodeHttp(url, {
method, method,
headers, headers,
body: normalizeRequestBody(options.body, headers['content-type']),
signal: controller.signal, signal: controller.signal,
...(body !== undefined ? { body } : {}),
}) })
const rawText = response.bodyText const rawText = response.bodyText
@@ -113,6 +113,13 @@ export async function upsertOpen91PendingOrder(payload: JsonObject = {}, config:
} }
const [item] = event.items const [item] = event.items
if (!item) {
throw createHttpError('91卡券订单商品明细为空', {
statusCode: 400,
errorCode: 'open91_order_item_required',
})
}
const orderItems = await replaceOrderItems(order.id, [ const orderItems = await replaceOrderItems(order.id, [
{ {
skuCode: item.skuCode, skuCode: item.skuCode,
+1 -1
View File
@@ -62,7 +62,7 @@ export function buildHealthPayload(startupState: StartupState, shutdownStarted:
export function formatStartupError(error: unknown) { export function formatStartupError(error: unknown) {
if (error instanceof Error && error.message) { if (error instanceof Error && error.message) {
return error.message.split("\n")[0].trim(); return error.message.split("\n")[0]?.trim() || "未知错误";
} }
return String(error || "未知错误").trim(); return String(error || "未知错误").trim();
+3 -3
View File
@@ -6,9 +6,9 @@
"allowJs": true, "allowJs": true,
"checkJs": true, "checkJs": true,
"noEmit": true, "noEmit": true,
"strict": false, "strict": true,
"noImplicitAny": true, "noUncheckedIndexedAccess": true,
"strictNullChecks": true, "exactOptionalPropertyTypes": true,
"skipLibCheck": true, "skipLibCheck": true,
"types": ["node"], "types": ["node"],
"lib": ["ES2022"] "lib": ["ES2022"]