优化后端代码质量基础
This commit is contained in:
@@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"semi": false,
|
||||||
|
"singleQuote": true,
|
||||||
|
"printWidth": 100,
|
||||||
|
"trailingComma": "all"
|
||||||
|
}
|
||||||
Generated
+17
@@ -15,6 +15,7 @@
|
|||||||
"@types/express": "^5.0.6",
|
"@types/express": "^5.0.6",
|
||||||
"@types/node": "^25.6.0",
|
"@types/node": "^25.6.0",
|
||||||
"@types/pg": "^8.20.0",
|
"@types/pg": "^8.20.0",
|
||||||
|
"prettier": "^3.8.3",
|
||||||
"tsx": "^4.22.3",
|
"tsx": "^4.22.3",
|
||||||
"typescript": "^6.0.2"
|
"typescript": "^6.0.2"
|
||||||
}
|
}
|
||||||
@@ -1299,6 +1300,22 @@
|
|||||||
"node": ">=0.10.0"
|
"node": ">=0.10.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/prettier": {
|
||||||
|
"version": "3.8.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/prettier/-/prettier-3.8.3.tgz",
|
||||||
|
"integrity": "sha512-7igPTM53cGHMW8xWuVTydi2KO233VFiTNyF5hLJqpilHfmn8C8gPf+PS7dUT64YcXFbiMGZxS9pCSxL/Dxm/Jw==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"bin": {
|
||||||
|
"prettier": "bin/prettier.cjs"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=14"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/prettier/prettier?sponsor=1"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/proxy-addr": {
|
"node_modules/proxy-addr": {
|
||||||
"version": "2.0.7",
|
"version": "2.0.7",
|
||||||
"resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz",
|
"resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz",
|
||||||
|
|||||||
@@ -8,6 +8,7 @@
|
|||||||
"build": "tsc -p tsconfig.build.json && rm -rf dist/db/migrations && mkdir -p dist/db && cp -R src/db/migrations dist/db/migrations",
|
"build": "tsc -p tsconfig.build.json && rm -rf dist/db/migrations && mkdir -p dist/db && cp -R src/db/migrations dist/db/migrations",
|
||||||
"db:migrate": "tsx src/db/migrate.ts",
|
"db:migrate": "tsx src/db/migrate.ts",
|
||||||
"dev": "tsx watch --clear-screen=false src/index.ts",
|
"dev": "tsx watch --clear-screen=false src/index.ts",
|
||||||
|
"format": "prettier --write .",
|
||||||
"test": "node --import tsx --test $(find src \\( -name '*.test.ts' -o -name '*.test.js' \\) -print)",
|
"test": "node --import tsx --test $(find src \\( -name '*.test.ts' -o -name '*.test.js' \\) -print)",
|
||||||
"typecheck": "tsc -p tsconfig.json --noEmit",
|
"typecheck": "tsc -p tsconfig.json --noEmit",
|
||||||
"start": "node dist/index.js",
|
"start": "node dist/index.js",
|
||||||
@@ -21,6 +22,7 @@
|
|||||||
"@types/express": "^5.0.6",
|
"@types/express": "^5.0.6",
|
||||||
"@types/node": "^25.6.0",
|
"@types/node": "^25.6.0",
|
||||||
"@types/pg": "^8.20.0",
|
"@types/pg": "^8.20.0",
|
||||||
|
"prettier": "^3.8.3",
|
||||||
"tsx": "^4.22.3",
|
"tsx": "^4.22.3",
|
||||||
"typescript": "^6.0.2"
|
"typescript": "^6.0.2"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -55,6 +55,7 @@ import {
|
|||||||
mapAdminCloudtentaclesSourceConfig,
|
mapAdminCloudtentaclesSourceConfig,
|
||||||
maskPhone,
|
maskPhone,
|
||||||
} from "./mappers.js";
|
} from "./mappers.js";
|
||||||
|
import { createHttpError } from "../../../../utils/http.js";
|
||||||
|
|
||||||
import type {
|
import type {
|
||||||
AdminCloudtentaclesCatalogQueryInput,
|
AdminCloudtentaclesCatalogQueryInput,
|
||||||
@@ -153,7 +154,10 @@ export function updateAdminCloudtentaclesSourceConfig(
|
|||||||
export function deleteAdminCloudtentaclesSource(sourceKey: string) {
|
export function deleteAdminCloudtentaclesSource(sourceKey: string) {
|
||||||
const key = String(sourceKey || "").trim();
|
const key = String(sourceKey || "").trim();
|
||||||
if (!key) {
|
if (!key) {
|
||||||
throw new Error("sourceKey is required for deletion");
|
throw createHttpError("cloudtentacles sourceKey 不能为空", {
|
||||||
|
statusCode: 400,
|
||||||
|
errorCode: "cloudtentacles_source_key_required",
|
||||||
|
});
|
||||||
}
|
}
|
||||||
deleteCloudtentaclesSessionStateByKey(key);
|
deleteCloudtentaclesSessionStateByKey(key);
|
||||||
deleteCloudtentaclesSourceByKey(key);
|
deleteCloudtentaclesSourceByKey(key);
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import { runtimeConfig } from '../../config/runtime.js'
|
import { runtimeConfig } from '../../config/runtime.js'
|
||||||
import { createClaimToken } from '../../repositories/claim-token-repo.js'
|
import { createClaimToken } from '../../repositories/claim-token-repo.js'
|
||||||
|
import { createHttpError } from '../../utils/http.js'
|
||||||
import { addHours, nowIso } from '../../utils/time.js'
|
import { addHours, nowIso } from '../../utils/time.js'
|
||||||
import { randomToken } from '../../utils/random.js'
|
import { randomToken } from '../../utils/random.js'
|
||||||
|
|
||||||
@@ -23,7 +24,10 @@ export async function createTaskClaimToken(taskId: number | string): Promise<Tas
|
|||||||
})
|
})
|
||||||
|
|
||||||
if (!token) {
|
if (!token) {
|
||||||
throw new Error('领取 token 创建失败')
|
throw createHttpError('领取 token 创建失败', {
|
||||||
|
statusCode: 500,
|
||||||
|
errorCode: 'claim_token_create_failed',
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import { createHttpError } from '../../utils/http.js'
|
|||||||
|
|
||||||
const DEFAULT_TIMEOUT_MS = 10000
|
const DEFAULT_TIMEOUT_MS = 10000
|
||||||
|
|
||||||
type JsonObject = Record<string, any>
|
type JsonObject = Record<string, unknown>
|
||||||
type BarkSendInput = {
|
type BarkSendInput = {
|
||||||
serverUrl?: string
|
serverUrl?: string
|
||||||
recipient?: {
|
recipient?: {
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import { sendInternalNotification } from './notification-service.js'
|
|||||||
const DEFAULT_COOLDOWN_MS = 10 * 60 * 1000
|
const DEFAULT_COOLDOWN_MS = 10 * 60 * 1000
|
||||||
const notificationCooldownMap = new Map<string, number>()
|
const notificationCooldownMap = new Map<string, number>()
|
||||||
|
|
||||||
type JsonObject = Record<string, any>
|
type JsonObject = Record<string, unknown>
|
||||||
type InternalNotificationPayload = {
|
type InternalNotificationPayload = {
|
||||||
title: string
|
title: string
|
||||||
body?: string
|
body?: string
|
||||||
@@ -13,6 +13,55 @@ type InternalNotificationPayload = {
|
|||||||
cooldownKey?: string
|
cooldownKey?: string
|
||||||
cooldownMs?: number
|
cooldownMs?: number
|
||||||
}
|
}
|
||||||
|
type KuaishouCloudAssetNotEnoughPayload = {
|
||||||
|
task?: unknown
|
||||||
|
flow?: unknown
|
||||||
|
assetBefore?: unknown
|
||||||
|
requiredAsset?: unknown
|
||||||
|
skuName?: unknown
|
||||||
|
}
|
||||||
|
type CloudtentaclesAuthExpiredPayload = {
|
||||||
|
pathname?: unknown
|
||||||
|
errorCode?: unknown
|
||||||
|
message?: unknown
|
||||||
|
cooldownSeconds?: unknown
|
||||||
|
sourceKey?: unknown
|
||||||
|
accountLabel?: unknown
|
||||||
|
}
|
||||||
|
type CloudtentaclesAssetLowPayload = {
|
||||||
|
asset?: unknown
|
||||||
|
threshold?: unknown
|
||||||
|
cooldownSeconds?: unknown
|
||||||
|
sourceKey?: unknown
|
||||||
|
accountLabel?: unknown
|
||||||
|
}
|
||||||
|
type Open91PendingConfigPayload = {
|
||||||
|
order?: unknown
|
||||||
|
orderNo?: unknown
|
||||||
|
productNo?: unknown
|
||||||
|
buyNum?: unknown
|
||||||
|
reason?: unknown
|
||||||
|
}
|
||||||
|
type TaskNotificationPayload = {
|
||||||
|
task?: unknown
|
||||||
|
reason?: unknown
|
||||||
|
source?: unknown
|
||||||
|
errorMessage?: unknown
|
||||||
|
}
|
||||||
|
type KuaishouCloudConsumeFailedPayload = {
|
||||||
|
task?: unknown
|
||||||
|
order?: unknown
|
||||||
|
ticketCodeMasked?: unknown
|
||||||
|
shopId?: unknown
|
||||||
|
shopName?: unknown
|
||||||
|
errorMessage?: unknown
|
||||||
|
}
|
||||||
|
type ClaimRedeemNeedsAttentionPayload = {
|
||||||
|
task?: unknown
|
||||||
|
order?: unknown
|
||||||
|
status?: unknown
|
||||||
|
errorMessage?: unknown
|
||||||
|
}
|
||||||
|
|
||||||
export async function notifyInternalSafely(payload: InternalNotificationPayload) {
|
export async function notifyInternalSafely(payload: InternalNotificationPayload) {
|
||||||
const cooldownKey = String(payload.cooldownKey || '').trim()
|
const cooldownKey = String(payload.cooldownKey || '').trim()
|
||||||
@@ -52,7 +101,7 @@ export function notifyKuaishouCloudAssetNotEnough({
|
|||||||
assetBefore = 0,
|
assetBefore = 0,
|
||||||
requiredAsset = 0,
|
requiredAsset = 0,
|
||||||
skuName = '',
|
skuName = '',
|
||||||
}: JsonObject = {}) {
|
}: KuaishouCloudAssetNotEnoughPayload = {}) {
|
||||||
const taskRecord = toRecord(task)
|
const taskRecord = toRecord(task)
|
||||||
const flowRecord = toRecord(flow)
|
const flowRecord = toRecord(flow)
|
||||||
const binding = toRecord(flowRecord.binding)
|
const binding = toRecord(flowRecord.binding)
|
||||||
@@ -81,7 +130,7 @@ export function notifyCloudtentaclesAuthExpired({
|
|||||||
cooldownSeconds = 600,
|
cooldownSeconds = 600,
|
||||||
sourceKey = '',
|
sourceKey = '',
|
||||||
accountLabel = '',
|
accountLabel = '',
|
||||||
}: JsonObject = {}) {
|
}: CloudtentaclesAuthExpiredPayload = {}) {
|
||||||
const normalizedSourceKey = String(sourceKey || '').trim()
|
const normalizedSourceKey = String(sourceKey || '').trim()
|
||||||
const normalizedAccountLabel = String(accountLabel || '').trim()
|
const normalizedAccountLabel = String(accountLabel || '').trim()
|
||||||
|
|
||||||
@@ -107,7 +156,7 @@ export function notifyCloudtentaclesAssetLow({
|
|||||||
cooldownSeconds = 1800,
|
cooldownSeconds = 1800,
|
||||||
sourceKey = '',
|
sourceKey = '',
|
||||||
accountLabel = '',
|
accountLabel = '',
|
||||||
}: JsonObject = {}) {
|
}: CloudtentaclesAssetLowPayload = {}) {
|
||||||
const normalizedSourceKey = String(sourceKey || '').trim()
|
const normalizedSourceKey = String(sourceKey || '').trim()
|
||||||
const normalizedAccountLabel = String(accountLabel || '').trim()
|
const normalizedAccountLabel = String(accountLabel || '').trim()
|
||||||
|
|
||||||
@@ -133,7 +182,7 @@ export function notifyOpen91PendingConfig({
|
|||||||
productNo = '',
|
productNo = '',
|
||||||
buyNum = 0,
|
buyNum = 0,
|
||||||
reason = '未命中履约配置',
|
reason = '未命中履约配置',
|
||||||
}: JsonObject = {}) {
|
}: Open91PendingConfigPayload = {}) {
|
||||||
const orderRecord = toRecord(order)
|
const orderRecord = toRecord(order)
|
||||||
|
|
||||||
return notifyInternalSafely({
|
return notifyInternalSafely({
|
||||||
@@ -152,7 +201,7 @@ export function notifyOpen91PendingConfig({
|
|||||||
export function notifyKuaishouCloudBindUrlRefreshFailed({
|
export function notifyKuaishouCloudBindUrlRefreshFailed({
|
||||||
task = {},
|
task = {},
|
||||||
errorMessage = '',
|
errorMessage = '',
|
||||||
}: JsonObject = {}) {
|
}: TaskNotificationPayload = {}) {
|
||||||
const taskRecord = toRecord(task)
|
const taskRecord = toRecord(task)
|
||||||
|
|
||||||
return notifyInternalSafely({
|
return notifyInternalSafely({
|
||||||
@@ -174,7 +223,7 @@ export function notifyKuaishouCloudConsumeFailed({
|
|||||||
shopId = '',
|
shopId = '',
|
||||||
shopName = '',
|
shopName = '',
|
||||||
errorMessage = '',
|
errorMessage = '',
|
||||||
}: JsonObject = {}) {
|
}: KuaishouCloudConsumeFailedPayload = {}) {
|
||||||
const taskRecord = toRecord(task)
|
const taskRecord = toRecord(task)
|
||||||
const orderRecord = toRecord(order)
|
const orderRecord = toRecord(order)
|
||||||
|
|
||||||
@@ -196,7 +245,7 @@ export function notifyTaskAutoManualReview({
|
|||||||
task = {},
|
task = {},
|
||||||
reason = '',
|
reason = '',
|
||||||
source = '',
|
source = '',
|
||||||
}: JsonObject = {}) {
|
}: TaskNotificationPayload = {}) {
|
||||||
const taskRecord = toRecord(task)
|
const taskRecord = toRecord(task)
|
||||||
|
|
||||||
return notifyInternalSafely({
|
return notifyInternalSafely({
|
||||||
@@ -216,7 +265,7 @@ export function notifyClaimRedeemNeedsAttention({
|
|||||||
order = {},
|
order = {},
|
||||||
status = '',
|
status = '',
|
||||||
errorMessage = '',
|
errorMessage = '',
|
||||||
}: JsonObject = {}) {
|
}: ClaimRedeemNeedsAttentionPayload = {}) {
|
||||||
const taskRecord = toRecord(task)
|
const taskRecord = toRecord(task)
|
||||||
const orderRecord = toRecord(order)
|
const orderRecord = toRecord(order)
|
||||||
|
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import { createHttpError } from '../../utils/http.js'
|
|||||||
const DEFAULT_WPUSH_ENDPOINT = 'https://api.wpush.cn/api/v1/send'
|
const DEFAULT_WPUSH_ENDPOINT = 'https://api.wpush.cn/api/v1/send'
|
||||||
const DEFAULT_TIMEOUT_MS = 10000
|
const DEFAULT_TIMEOUT_MS = 10000
|
||||||
|
|
||||||
type JsonObject = Record<string, any>
|
type JsonObject = Record<string, unknown>
|
||||||
type NodeHttpResponse = {
|
type NodeHttpResponse = {
|
||||||
ok: boolean
|
ok: boolean
|
||||||
status: number
|
status: number
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import { runtimeConfig } from '../../config/runtime.js'
|
import { runtimeConfig } from '../../config/runtime.js'
|
||||||
import { createHttpError } from '../../utils/http.js'
|
import { createHttpError } from '../../utils/http.js'
|
||||||
|
import type { RuntimeConfig } from '../../types/runtime-config.js'
|
||||||
|
|
||||||
export const OPEN_91_PROVIDER = '91kaquan'
|
export const OPEN_91_PROVIDER = '91kaquan'
|
||||||
export const OPEN_91_PLATFORM = 'kuaishou'
|
export const OPEN_91_PLATFORM = 'kuaishou'
|
||||||
@@ -7,10 +8,13 @@ export const OPEN_91_SUCCESS_MESSAGE = '接口调用成功'
|
|||||||
export const OPEN_91_DEFAULT_FAIL_CODE = 1204
|
export const OPEN_91_DEFAULT_FAIL_CODE = 1204
|
||||||
export const OPEN_91_COST_EXCEED_FAIL_CODE = 1220
|
export const OPEN_91_COST_EXCEED_FAIL_CODE = 1220
|
||||||
|
|
||||||
type JsonObject = Record<string, any>
|
type Open91RuntimeConfig = RuntimeConfig['platforms']['ninetyone']
|
||||||
|
|
||||||
export function getOpen91Config() {
|
export function getOpen91Config(overrides: Partial<Open91RuntimeConfig> = {}) {
|
||||||
const config = (runtimeConfig.platforms?.ninetyone || {}) as JsonObject
|
const config = {
|
||||||
|
...(runtimeConfig.platforms?.ninetyone || {}),
|
||||||
|
...overrides,
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
userId: String(config.userId || '').trim(),
|
userId: String(config.userId || '').trim(),
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import { syncDeliveryTasksForOrder } from './delivery-task-service.js'
|
|||||||
import { resolveOrderItemForFulfillment } from './product-match-service.js'
|
import { resolveOrderItemForFulfillment } from './product-match-service.js'
|
||||||
import { nowIso } from '../../utils/time.js'
|
import { nowIso } from '../../utils/time.js'
|
||||||
import { logIntegration } from '../../utils/logger.js'
|
import { logIntegration } from '../../utils/logger.js'
|
||||||
|
import { createHttpError } from '../../utils/http.js'
|
||||||
import type { OrderItemRow, OrderRow, TaskRow } from '../../types/repository/rows.js'
|
import type { OrderItemRow, OrderRow, TaskRow } from '../../types/repository/rows.js'
|
||||||
|
|
||||||
type SourceOrderItem = {
|
type SourceOrderItem = {
|
||||||
@@ -173,7 +174,10 @@ export async function upsertOrderFromSource(
|
|||||||
})
|
})
|
||||||
|
|
||||||
if (!order) {
|
if (!order) {
|
||||||
throw new Error('订单写入失败')
|
throw createHttpError('订单写入失败', {
|
||||||
|
statusCode: 500,
|
||||||
|
errorCode: 'order_write_failed',
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const orderItems = await replaceOrderItems(
|
const orderItems = await replaceOrderItems(
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import fs from 'node:fs'
|
|||||||
import path from 'node:path'
|
import path from 'node:path'
|
||||||
|
|
||||||
import { PROJECT_ROOT } from '../../../config/runtime.js'
|
import { PROJECT_ROOT } from '../../../config/runtime.js'
|
||||||
|
import { createHttpError } from '../../../utils/http.js'
|
||||||
|
|
||||||
const CLOUDTENTACLES_SESSION_FILE_PATH = path.join(PROJECT_ROOT, 'data', 'cloudtentacles-session.json')
|
const CLOUDTENTACLES_SESSION_FILE_PATH = path.join(PROJECT_ROOT, 'data', 'cloudtentacles-session.json')
|
||||||
|
|
||||||
@@ -58,7 +59,10 @@ export function saveCloudtentaclesSessionState(rawValue: unknown) {
|
|||||||
export function saveCloudtentaclesSessionStateByKey(sourceKey: unknown, rawValue: unknown) {
|
export function saveCloudtentaclesSessionStateByKey(sourceKey: unknown, rawValue: unknown) {
|
||||||
const key = String(sourceKey || '').trim()
|
const key = String(sourceKey || '').trim()
|
||||||
if (!key) {
|
if (!key) {
|
||||||
throw new Error('saveCloudtentaclesSessionStateByKey: sourceKey is required')
|
throw createHttpError('cloudtentacles sourceKey 不能为空', {
|
||||||
|
statusCode: 400,
|
||||||
|
errorCode: 'cloudtentacles_source_key_required',
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const states = loadCloudtentaclesSessionStatesFromFile()
|
const states = loadCloudtentaclesSessionStatesFromFile()
|
||||||
@@ -75,7 +79,10 @@ export function saveCloudtentaclesSessionStateByKey(sourceKey: unknown, rawValue
|
|||||||
export function deleteCloudtentaclesSessionStateByKey(sourceKey: unknown) {
|
export function deleteCloudtentaclesSessionStateByKey(sourceKey: unknown) {
|
||||||
const key = String(sourceKey || '').trim()
|
const key = String(sourceKey || '').trim()
|
||||||
if (!key) {
|
if (!key) {
|
||||||
throw new Error('deleteCloudtentaclesSessionStateByKey: sourceKey is required')
|
throw createHttpError('cloudtentacles sourceKey 不能为空', {
|
||||||
|
statusCode: 400,
|
||||||
|
errorCode: 'cloudtentacles_source_key_required',
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const states = loadCloudtentaclesSessionStatesFromFile()
|
const states = loadCloudtentaclesSessionStatesFromFile()
|
||||||
@@ -99,7 +106,10 @@ export function clearCloudtentaclesSessionState() {
|
|||||||
export function clearCloudtentaclesSessionStateByKey(sourceKey: unknown) {
|
export function clearCloudtentaclesSessionStateByKey(sourceKey: unknown) {
|
||||||
const key = String(sourceKey || '').trim()
|
const key = String(sourceKey || '').trim()
|
||||||
if (!key) {
|
if (!key) {
|
||||||
throw new Error('clearCloudtentaclesSessionStateByKey: sourceKey is required')
|
throw createHttpError('cloudtentacles sourceKey 不能为空', {
|
||||||
|
statusCode: 400,
|
||||||
|
errorCode: 'cloudtentacles_source_key_required',
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const cleared = createDefaultCloudtentaclesSessionState()
|
const cleared = createDefaultCloudtentaclesSessionState()
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import fs from 'node:fs'
|
|||||||
import path from 'node:path'
|
import path from 'node:path'
|
||||||
|
|
||||||
import { PROJECT_ROOT } from '../../../config/runtime.js'
|
import { PROJECT_ROOT } from '../../../config/runtime.js'
|
||||||
|
import { createHttpError } from '../../../utils/http.js'
|
||||||
|
|
||||||
const CLOUDTENTACLES_SOURCES_FILE_PATH = path.join(PROJECT_ROOT, 'data', 'cloudtentacles-sources.json')
|
const CLOUDTENTACLES_SOURCES_FILE_PATH = path.join(PROJECT_ROOT, 'data', 'cloudtentacles-sources.json')
|
||||||
|
|
||||||
@@ -63,7 +64,10 @@ export function saveCloudtentaclesSourcesList(rawValue: unknown) {
|
|||||||
export function saveCloudtentaclesSourceByKey(sourceKey: unknown, data: JsonObject = {}) {
|
export function saveCloudtentaclesSourceByKey(sourceKey: unknown, data: JsonObject = {}) {
|
||||||
const key = String(sourceKey || '').trim()
|
const key = String(sourceKey || '').trim()
|
||||||
if (!key) {
|
if (!key) {
|
||||||
throw new Error('saveCloudtentaclesSourceByKey: sourceKey is required')
|
throw createHttpError('cloudtentacles sourceKey 不能为空', {
|
||||||
|
statusCode: 400,
|
||||||
|
errorCode: 'cloudtentacles_source_key_required',
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const config = loadCloudtentaclesSourcesConfigFromFile()
|
const config = loadCloudtentaclesSourcesConfigFromFile()
|
||||||
@@ -87,10 +91,16 @@ export function saveCloudtentaclesSourceByKey(sourceKey: unknown, data: JsonObje
|
|||||||
export function deleteCloudtentaclesSourceByKey(sourceKey: unknown) {
|
export function deleteCloudtentaclesSourceByKey(sourceKey: unknown) {
|
||||||
const key = String(sourceKey || '').trim()
|
const key = String(sourceKey || '').trim()
|
||||||
if (!key) {
|
if (!key) {
|
||||||
throw new Error('deleteCloudtentaclesSourceByKey: sourceKey is required')
|
throw createHttpError('cloudtentacles sourceKey 不能为空', {
|
||||||
|
statusCode: 400,
|
||||||
|
errorCode: 'cloudtentacles_source_key_required',
|
||||||
|
})
|
||||||
}
|
}
|
||||||
if (key === 'default') {
|
if (key === 'default') {
|
||||||
throw new Error('deleteCloudtentaclesSourceByKey: cannot delete the default source')
|
throw createHttpError('不能删除默认 cloudtentacles 账号', {
|
||||||
|
statusCode: 409,
|
||||||
|
errorCode: 'cloudtentacles_default_source_forbidden',
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const config = loadCloudtentaclesSourcesConfigFromFile()
|
const config = loadCloudtentaclesSourcesConfigFromFile()
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import { logError, logInfo, logWarn } from '../../utils/logger.js'
|
import { logError, logInfo, logWarn } from '../../utils/logger.js'
|
||||||
|
import { createHttpError } from '../../utils/http.js'
|
||||||
import {
|
import {
|
||||||
getCloudtentaclesHealthJob,
|
getCloudtentaclesHealthJob,
|
||||||
getScheduledJobsConfig,
|
getScheduledJobsConfig,
|
||||||
@@ -53,7 +54,10 @@ export async function runScheduledJobNow(jobId: unknown) {
|
|||||||
const job = config.jobs.find((item) => String(item.id || '').trim() === String(jobId || '').trim())
|
const job = config.jobs.find((item) => String(item.id || '').trim() === String(jobId || '').trim())
|
||||||
|
|
||||||
if (!job) {
|
if (!job) {
|
||||||
throw new Error('定时任务不存在')
|
throw createHttpError('定时任务不存在', {
|
||||||
|
statusCode: 404,
|
||||||
|
errorCode: 'scheduled_job_not_found',
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const currentTimer = timers.get(job.id)
|
const currentTimer = timers.get(job.id)
|
||||||
@@ -171,7 +175,10 @@ function dispatchJob(job: JsonObject) {
|
|||||||
return runCloudtentaclesHealthJob(job)
|
return runCloudtentaclesHealthJob(job)
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new Error(`不支持的定时任务类型:${job.type}`)
|
throw createHttpError(`不支持的定时任务类型:${job.type}`, {
|
||||||
|
statusCode: 400,
|
||||||
|
errorCode: 'unsupported_scheduled_job_type',
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateJobState(jobId: string, patch: JsonObject) {
|
function updateJobState(jobId: string, patch: JsonObject) {
|
||||||
|
|||||||
Reference in New Issue
Block a user