统一前后端代码格式化配置

This commit is contained in:
yml2213
2026-08-16 17:27:12 +08:00
parent 8705f6a6a1
commit 5c7c3e14e3
278 changed files with 6386 additions and 5500 deletions
@@ -1,9 +1,17 @@
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'
import {
normalizeDateQuery,
normalizePage,
normalizePageSize,
safeParseJson,
} from './admin-query-utils.js'
import type { JsonObject } from '../../types/json.js'
export async function writeAdminAuditLog(session: JsonObject | null | undefined, payload: JsonObject = {}) {
export async function writeAdminAuditLog(
session: JsonObject | null | undefined,
payload: JsonObject = {},
) {
if (!session?.userId) {
return null
}
@@ -32,10 +32,14 @@ type AdminUserStatus = 'active' | 'disabled'
export async function ensureAdminUsersBootstrapped(): Promise<void> {
ensureAdminAuthConfigured()
const configuredUsers = Array.isArray(runtimeConfig.admin?.defaultUsers) ? runtimeConfig.admin.defaultUsers : []
const configuredUsers = Array.isArray(runtimeConfig.admin?.defaultUsers)
? runtimeConfig.admin.defaultUsers
: []
for (const configuredUser of configuredUsers) {
const username = String(configuredUser?.username || '').trim().toLowerCase()
const username = String(configuredUser?.username || '')
.trim()
.toLowerCase()
const password = String(configuredUser?.password || '').trim()
const role = normalizeAdminRole(configuredUser?.role)
@@ -70,7 +74,9 @@ export async function loginAdmin(
): Promise<JsonObject> {
ensureAdminAuthConfigured()
const normalizedUsername = String(username || '').trim().toLowerCase()
const normalizedUsername = String(username || '')
.trim()
.toLowerCase()
const normalizedPassword = String(password || '').trim()
if (!normalizedUsername || !normalizedPassword) {
@@ -87,7 +93,11 @@ export async function loginAdmin(
}
const user = await getAdminUserByUsername(normalizedUsername)
if (!user || user.status !== 'active' || !verifyAdminPassword(normalizedPassword, user.password_hash)) {
if (
!user ||
user.status !== 'active' ||
!verifyAdminPassword(normalizedPassword, user.password_hash)
) {
await recordAdminLoginLog({
userId: user ? Number(user.id) : null,
username: normalizedUsername,
@@ -201,7 +211,10 @@ export async function getAdminSessionSummary(token: unknown): Promise<JsonObject
}
}
export function requireAdminRole(session: { role?: string } | null | undefined, allowedRoles: string[]): void {
export function requireAdminRole(
session: { role?: string } | null | undefined,
allowedRoles: string[],
): void {
if (session && allowedRoles.includes(session.role || '')) {
return
}
@@ -342,7 +355,10 @@ export async function updateManagedAdminUserStatus(
}
}
export async function resetManagedAdminUserPassword(userId: number | string, payload: JsonObject = {}): Promise<JsonObject> {
export async function resetManagedAdminUserPassword(
userId: number | string,
payload: JsonObject = {},
): Promise<JsonObject> {
const user = await getRequiredAdminUser(userId)
const password = normalizePassword(payload.password)
@@ -373,7 +389,9 @@ export async function resetManagedAdminUserPassword(userId: number | string, pay
export function ensureAdminAuthConfigured(): void {
const sessionSecret = String(runtimeConfig.admin?.sessionSecret || '').trim()
const configuredUsers = Array.isArray(runtimeConfig.admin?.defaultUsers) ? runtimeConfig.admin.defaultUsers : []
const configuredUsers = Array.isArray(runtimeConfig.admin?.defaultUsers)
? runtimeConfig.admin.defaultUsers
: []
if (sessionSecret && configuredUsers.length > 0) {
return
@@ -435,7 +453,9 @@ function signPayload(encodedPayload: string): string {
}
export function normalizeAdminRole(role: unknown): AdminRole {
const normalized = String(role || '').trim().toLowerCase()
const normalized = String(role || '')
.trim()
.toLowerCase()
if (normalized === 'admin') {
return 'admin'
@@ -449,7 +469,11 @@ export function normalizeAdminRole(role: unknown): AdminRole {
}
export function normalizeAdminUserStatus(status: unknown): AdminUserStatus {
return String(status || '').trim().toLowerCase() === 'disabled' ? 'disabled' : 'active'
return String(status || '')
.trim()
.toLowerCase() === 'disabled'
? 'disabled'
: 'active'
}
function safeCompare(input: unknown, expected: unknown): boolean {
@@ -464,17 +488,23 @@ function safeCompare(input: unknown, expected: unknown): boolean {
}
function normalizeRoleQuery(role: unknown): string {
const normalized = String(role || '').trim().toLowerCase()
const normalized = String(role || '')
.trim()
.toLowerCase()
return ['admin', 'operator', 'support'].includes(normalized) ? normalized : ''
}
function normalizeStatusQuery(status: unknown): string {
const normalized = String(status || '').trim().toLowerCase()
const normalized = String(status || '')
.trim()
.toLowerCase()
return ['active', 'disabled'].includes(normalized) ? normalized : ''
}
function normalizeUsername(username: unknown): string {
return String(username || '').trim().toLowerCase()
return String(username || '')
.trim()
.toLowerCase()
}
function normalizePassword(password: unknown): string {
@@ -523,7 +553,7 @@ async function getRequiredAdminUser(userId: number | string): Promise<AdminUserR
async function ensureAdminUserChangeAllowed(
user: AdminUserRow,
options: { nextRole?: AdminRole, nextStatus?: AdminUserStatus } = {},
options: { nextRole?: AdminRole; nextStatus?: AdminUserStatus } = {},
session: AdminSession,
): Promise<void> {
const nextRole = options.nextRole || user.role
@@ -536,7 +566,11 @@ async function ensureAdminUserChangeAllowed(
})
}
if (user.role === 'admin' && (nextRole !== 'admin' || nextStatus !== 'active') && await countActiveAdminUsers() <= 1) {
if (
user.role === 'admin' &&
(nextRole !== 'admin' || nextStatus !== 'active') &&
(await countActiveAdminUsers()) <= 1
) {
throw createHttpError('至少保留一个启用中的管理员账号', {
statusCode: 409,
errorCode: 'admin_user_last_admin_not_allowed',
@@ -555,11 +589,13 @@ function mapAdminUser(user: AdminUserRow): JsonObject {
}
}
function pickLoginMeta(meta: {
ip?: string
userAgent?: string
location?: string
} = {}) {
function pickLoginMeta(
meta: {
ip?: string
userAgent?: string
location?: string
} = {},
) {
const result: {
ip?: string
userAgent?: string
@@ -11,15 +11,8 @@ export async function getAdminDashboardSummary() {
TASK_STATUS.PENDING_BINDING_PREPARE,
TASK_STATUS.WAITING_BINDING,
]
const claimingStatuses = [
TASK_STATUS.CLAIMED,
TASK_STATUS.ROLE_CONFIRMED,
TASK_STATUS.REDEEMING,
]
const abnormalStatuses = [
TASK_STATUS.RETRY_PENDING,
TASK_STATUS.MANUAL_REVIEW,
]
const claimingStatuses = [TASK_STATUS.CLAIMED, TASK_STATUS.ROLE_CONFIRMED, TASK_STATUS.REDEEMING]
const abnormalStatuses = [TASK_STATUS.RETRY_PENDING, TASK_STATUS.MANUAL_REVIEW]
const result = await query(
`
SELECT
@@ -1,17 +1,10 @@
import type { Request } from 'express'
import type { JsonObject } from '../../types/json.js'
import {
createAdminLoginLog,
listAdminLoginLogs,
} from '../../repositories/admin-login-log-repo.js'
import { createAdminLoginLog, listAdminLoginLogs } from '../../repositories/admin-login-log-repo.js'
import { logWarn } from '../../utils/logger.js'
import { nowIso } from '../../utils/time.js'
import {
normalizeDateQuery,
normalizePage,
normalizePageSize,
} from './admin-query-utils.js'
import { normalizeDateQuery, normalizePage, normalizePageSize } from './admin-query-utils.js'
type RecordAdminLoginInput = {
userId?: number | null
@@ -108,16 +101,8 @@ export function resolveClientLocation(req: Request) {
'cloudfront-viewer-country',
'x-country-code',
])
const city = firstHeader(req, [
'cf-ipcity',
'x-vercel-ip-city',
'x-city',
])
const region = firstHeader(req, [
'cf-region',
'x-vercel-ip-country-region',
'x-region',
])
const city = firstHeader(req, ['cf-ipcity', 'x-vercel-ip-city', 'x-city'])
const region = firstHeader(req, ['cf-region', 'x-vercel-ip-country-region', 'x-region'])
return [country, region, city].filter(Boolean).join(' · ')
}
@@ -34,7 +34,10 @@ export async function mapAdminOrderListItem(item: OrderListRow): Promise<AdminOr
createdAt: item.created_at,
updatedAt: item.updated_at,
itemCount: orderItems.length,
totalQuantity: orderItems.reduce((sum, orderItem) => sum + Math.max(1, Number(orderItem.quantity || 1)), 0),
totalQuantity: orderItems.reduce(
(sum, orderItem) => sum + Math.max(1, Number(orderItem.quantity || 1)),
0,
),
itemSummary,
taskCount: Number(item.task_count || tasks.length || 0),
resourceStatus: fulfillmentProgress.resourceStatus,
@@ -52,8 +55,9 @@ export function summarizeOrderItems(items: OrderItemRow[] | null | undefined): s
}
const [firstItem] = normalizedItems
const firstLabel = resolveOrderItemTitle(firstItem)
|| String(firstItem?.sku_name || firstItem?.sku_code || '').trim()
const firstLabel =
resolveOrderItemTitle(firstItem) ||
String(firstItem?.sku_name || firstItem?.sku_code || '').trim()
if (normalizedItems.length === 1) {
return firstLabel
@@ -66,10 +66,7 @@ import type {
AdminTaskListQueryInput,
AdminViewerSessionInput,
} from '../../types/admin/read-inputs.js'
import type {
KuaishouIndustryVoucherRow,
TaskRow,
} from '../../types/repository/rows.js'
import type { KuaishouIndustryVoucherRow, TaskRow } from '../../types/repository/rows.js'
export async function getAdminOrders(
query: AdminOrderListQueryInput = {},
@@ -229,15 +226,16 @@ export async function getAdminTaskDetail(
}
const primaryClaimTokenId = getTaskPrimaryClaimTokenId(task)
const [order, claimToken, taskEvents, taskKuaishouIndustryVouchers, oidKuaishouIndustryVouchers] = await Promise.all([
getOrderById(task.order_id),
primaryClaimTokenId ? getClaimTokenById(primaryClaimTokenId) : Promise.resolve(null),
listTaskEventsByTaskId(task.id),
listKuaishouIndustryVouchersByTaskId(task.id),
task.platform_order_id
? listKuaishouIndustryVouchersByOid(task.platform_order_id)
: Promise.resolve([]),
])
const [order, claimToken, taskEvents, taskKuaishouIndustryVouchers, oidKuaishouIndustryVouchers] =
await Promise.all([
getOrderById(task.order_id),
primaryClaimTokenId ? getClaimTokenById(primaryClaimTokenId) : Promise.resolve(null),
listTaskEventsByTaskId(task.id),
listKuaishouIndustryVouchersByTaskId(task.id),
task.platform_order_id
? listKuaishouIndustryVouchersByOid(task.platform_order_id)
: Promise.resolve([]),
])
const orderItems = order ? await listOrderItemsByOrderId(order.id) : []
const orderItem = orderItems.find((item) => item.id === task.order_item_id) || null
const taskContext = parseTaskContext(task)
@@ -252,10 +250,7 @@ export async function getAdminTaskDetail(
cloudSourceLabelMap,
}) || mapKuaishouCloudTaskStateProjection(task, { cloudSourceLabelMap })
const claimIdentity = buildClaimIdentityAdminSummary(taskContext, {
flowLike:
taskContext.kuaishouCloudFulfillment ||
taskContext.kuaishouFeifei ||
null,
flowLike: taskContext.kuaishouCloudFulfillment || taskContext.kuaishouFeifei || null,
taskRoleId: task.role_id,
taskRoleName: task.role_name,
})
@@ -265,17 +260,20 @@ export async function getAdminTaskDetail(
taskKuaishouIndustryVouchers,
oidKuaishouIndustryVouchers,
)
const kuaishouIndustryVoucher =
firstKuaishouIndustryVoucher
? mapAdminKuaishouIndustryVoucher(firstKuaishouIndustryVoucher)
: mapKuaishouIndustryVoucherContext(taskContext.kuaishouIndustryVoucher)
const kuaishouIndustryVoucher = firstKuaishouIndustryVoucher
? mapAdminKuaishouIndustryVoucher(firstKuaishouIndustryVoucher)
: mapKuaishouIndustryVoucherContext(taskContext.kuaishouIndustryVoucher)
const hasKuaishouIndustryVoucher = Boolean(
kuaishouIndustryVoucher && String(kuaishouIndustryVoucher.voucherCode || '').trim(),
)
const kuaishouIndustryVoucherStatus =
String(kuaishouIndustryVoucher?.status || '').trim().toUpperCase()
const kuaishouIndustryVoucherSendCallbackStatus =
String(kuaishouIndustryVoucher?.sendCallbackStatus || '').trim().toLowerCase()
const kuaishouIndustryVoucherStatus = String(kuaishouIndustryVoucher?.status || '')
.trim()
.toUpperCase()
const kuaishouIndustryVoucherSendCallbackStatus = String(
kuaishouIndustryVoucher?.sendCallbackStatus || '',
)
.trim()
.toLowerCase()
return {
task: mapAdminTaskListItem(
@@ -435,7 +433,7 @@ function resolveKuaishouIndustryVoucherForTask(
taskContext.kuaishouIndustryVoucher &&
typeof taskContext.kuaishouIndustryVoucher === 'object' &&
!Array.isArray(taskContext.kuaishouIndustryVoucher)
? taskContext.kuaishouIndustryVoucher as JsonRecord
? (taskContext.kuaishouIndustryVoucher as JsonRecord)
: {}
const voucherCode = String(voucherContext.voucherCode || voucherContext.eticketId || '').trim()
if (voucherCode) {
@@ -457,7 +455,7 @@ function resolveKuaishouIndustryVoucherForTask(
}
}
return oidVouchers.length === 1 ? (oidVouchers[0] || null) : null
return oidVouchers.length === 1 ? oidVouchers[0] || null : null
}
function buildCloudSourceLabelMap() {
@@ -15,7 +15,10 @@ test('resolveAdminTaskScreenshotUrl lets support view final redeemed screenshot'
runtime_session_id: '',
}
const screenshotUrl = await resolveAdminTaskScreenshotUrl(task, createAdminViewerContext({ role: 'support' }))
const screenshotUrl = await resolveAdminTaskScreenshotUrl(
task,
createAdminViewerContext({ role: 'support' }),
)
assert.equal(screenshotUrl, '/api/v1/admin/tasks/12/screenshot')
})
@@ -27,7 +30,10 @@ test('resolveAdminTaskScreenshotUrl falls back to review screenshot when runtime
runtime_session_id: 'runtime-session-13',
}
const screenshotUrl = await resolveAdminTaskScreenshotUrl(task, createAdminViewerContext({ role: 'support' }))
const screenshotUrl = await resolveAdminTaskScreenshotUrl(
task,
createAdminViewerContext({ role: 'support' }),
)
assert.equal(screenshotUrl, '/api/v1/admin/tasks/13/screenshot')
})
@@ -1,6 +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 { asJsonObject, type JsonObject, JsonRecord } from '../../types/json.js'
import {
parseTaskContext as parseTaskContextValue,
parseTaskState as parseTaskStateValue,
@@ -79,8 +79,7 @@ export function mapKuaishouCloudFulfillmentContext(
const role = asJsonObject(record.role)
const purchase = asJsonObject(record.purchase)
const dispatch = asJsonObject(record.dispatch)
const returnNumber =
asJsonObject(record.returnNumber)
const returnNumber = asJsonObject(record.returnNumber)
const consume = asJsonObject(record.consume)
const cloudSourceKeys = Array.isArray(binding.cloudSourceKeys)
? binding.cloudSourceKeys.map((value: unknown) => String(value || '').trim()).filter(Boolean)
@@ -373,7 +372,8 @@ export function createAdminViewerContext(
canViewSensitiveTaskData: role === 'admin' || role === 'operator',
canManageTaskLifecycle: role === 'admin' || role === 'operator',
canOperateAssistedTask: role === 'admin' || role === 'operator' || role === 'support',
canOperateKuaishouIndustryVoucher: role === 'admin' || role === 'operator' || role === 'support',
canOperateKuaishouIndustryVoucher:
role === 'admin' || role === 'operator' || role === 'support',
}
}
@@ -1,7 +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 { asJsonObject, type JsonObject, JsonRecord } from '../../types/json.js'
import {
TASK_STATUS,
isTaskFulfillmentCompletedStatus,
@@ -17,10 +17,7 @@ import type {
AdminTaskListItem,
} from '../../types/admin/read-models.js'
import type { AdminTaskActionPayload } from '../../types/admin/write-models.js'
import type {
TaskEventRow,
TaskRow,
} from '../../types/repository/rows.js'
import type { TaskEventRow, TaskRow } from '../../types/repository/rows.js'
import type { AdminViewerContext } from './admin-read-shared-helpers.js'
type TaskFulfillmentState = {
@@ -28,9 +25,7 @@ type TaskFulfillmentState = {
customerStatus: string
}
export function mapAdminTaskSummary(
task: TaskRow,
): JsonRecord {
export function mapAdminTaskSummary(task: TaskRow): JsonRecord {
const fulfillment = buildTaskFulfillmentState(task)
return {
@@ -111,8 +106,10 @@ export function mapAdminTaskListItem(
lastError: task.last_error,
createdAt: task.created_at,
updatedAt: task.updated_at,
claimToken: viewerContext.canViewSensitiveTaskData ? (task.primary_claim_token || task.claim_token || '') : '',
screenshotPath: viewerContext.role === 'support' ? '' : (task.screenshot_path || ''),
claimToken: viewerContext.canViewSensitiveTaskData
? task.primary_claim_token || task.claim_token || ''
: '',
screenshotPath: viewerContext.role === 'support' ? '' : task.screenshot_path || '',
}
}
@@ -134,7 +131,9 @@ export function buildOrderFulfillmentProgress(
const totalTaskCount = normalizedTasks.length
const taskFulfillments = normalizedTasks.map((task) => buildTaskFulfillmentState(task))
const preparedTaskCount = normalizedTasks.filter((task) => isTaskResourcePrepared(task)).length
const completedTaskCount = normalizedTasks.filter((task) => isTaskFulfillmentCompleted(task)).length
const completedTaskCount = normalizedTasks.filter((task) =>
isTaskFulfillmentCompleted(task),
).length
let resourceStatus = 'pending_prepare'
let customerStatus = 'not_started'
@@ -152,7 +151,11 @@ export function buildOrderFulfillmentProgress(
if (normalizedTasks.every((task) => isTaskFulfillmentCompleted(task))) {
resourceStatus = 'resource_ready'
customerStatus = 'customer_completed'
} else if (taskFulfillments.some((item) => ['customer_processing', 'customer_confirmed', 'link_opened'].includes(item.customerStatus))) {
} else if (
taskFulfillments.some((item) =>
['customer_processing', 'customer_confirmed', 'link_opened'].includes(item.customerStatus),
)
) {
resourceStatus = preparedTaskCount > 0 ? 'resource_ready' : 'pending_prepare'
customerStatus = 'customer_processing'
} else if (taskFulfillments.some((item) => item.customerStatus === 'waiting_customer')) {
@@ -163,7 +166,11 @@ export function buildOrderFulfillmentProgress(
customerStatus = 'customer_exception'
} else if (preparedTaskCount > 0) {
resourceStatus = 'resource_ready'
} else if (taskFulfillments.some((item) => ['manual_review', 'retry_pending'].includes(item.resourceStatus))) {
} else if (
taskFulfillments.some((item) =>
['manual_review', 'retry_pending'].includes(item.resourceStatus),
)
) {
resourceStatus = 'resource_exception'
}
@@ -1,8 +1,6 @@
import { getAffiliateDashConfig } from '../../platforms/affiliate-dash/config.js'
import type { JsonObject } from '../../../types/json.js'
import {
getAffiliateDashWallet,
} from '../../platforms/affiliate-dash/order-service.js'
import { getAffiliateDashWallet } from '../../platforms/affiliate-dash/order-service.js'
import { listAffiliateDashProducts } from '../../platforms/affiliate-dash/product-service.js'
import {
getAffiliateDashSourceConfig,
@@ -35,9 +33,7 @@ export async function updateAdminAffiliateDashConfig(payload: JsonObject = {}) {
export function matchAdminAffiliateDashSku(payload: JsonObject = {}) {
const productNo = String(payload.productNo || payload.product_no || '').trim()
const source = getAdminEditableAffiliateDashConfig()
const sku = productNo
? String(source.skuMapping[productNo] || '').trim()
: ''
const sku = productNo ? String(source.skuMapping[productNo] || '').trim() : ''
return {
productNo,
@@ -52,7 +52,13 @@ test('resolveCloudtentaclesAdminContext merges payload source and persisted sess
test('hasCloudtentaclesCredentialContextChanged detects normalized credential changes', () => {
assert.equal(
hasCloudtentaclesCredentialContextChanged(
{ baseUrl: ' https://a ', username: 'u1', phone: '13812345678', deviceId: 'd1', deviceType: 1 },
{
baseUrl: ' https://a ',
username: 'u1',
phone: '13812345678',
deviceId: 'd1',
deviceType: 1,
},
{ baseUrl: 'https://a', username: 'u1', phone: '13812345678', deviceId: 'd1', deviceType: 1 },
),
false,
@@ -1,70 +1,57 @@
export function pickFirstNonEmpty(values: unknown[]) {
for (const value of values) {
const normalized = String(value || "").trim();
const normalized = String(value || '').trim()
if (normalized) {
return normalized;
return normalized
}
}
return "";
return ''
}
export function isPlainObject(value: unknown): value is JsonObject {
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
return Boolean(value) && typeof value === 'object' && !Array.isArray(value)
}
import { getCloudtentaclesSourceByKey } from "../../../platforms/cloudtentacles/source-config-service.js";
import { getCloudtentaclesSessionStateByKey } from "../../../platforms/cloudtentacles/session-state-service.js";
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,
} from "../../../platforms/cloudtentacles/defaults.js";
} from '../../../platforms/cloudtentacles/defaults.js'
export function resolveCloudtentaclesAdminContext(payload: JsonObject = {}, options: JsonObject = {}) {
const sourceKey = String(
payload.sourceKey || options.sourceKey || "default"
).trim();
const savedSource = options.savedSource || getCloudtentaclesSourceByKey(sourceKey) || {};
const persistedSession = options.persistedSession ||
getCloudtentaclesSessionStateByKey(sourceKey) ||
{};
const defaultBaseUrl = String(
options.defaultBaseUrl || "https://123.207.217.176"
).trim();
export function resolveCloudtentaclesAdminContext(
payload: JsonObject = {},
options: JsonObject = {},
) {
const sourceKey = String(payload.sourceKey || options.sourceKey || 'default').trim()
const savedSource = options.savedSource || getCloudtentaclesSourceByKey(sourceKey) || {}
const persistedSession =
options.persistedSession || getCloudtentaclesSessionStateByKey(sourceKey) || {}
const defaultBaseUrl = String(options.defaultBaseUrl || 'https://123.207.217.176').trim()
return {
sourceKey,
baseUrl: pickFirstNonEmpty([
payload.baseUrl,
savedSource.baseUrl,
defaultBaseUrl,
]),
baseUrl: pickFirstNonEmpty([payload.baseUrl, savedSource.baseUrl, defaultBaseUrl]),
token: pickFirstNonEmpty([payload.token, persistedSession.token]),
deviceId: normalizeCloudtentaclesDeviceId(
pickFirstNonEmpty([
payload.deviceId,
savedSource.deviceId,
persistedSession.deviceId,
])
pickFirstNonEmpty([payload.deviceId, savedSource.deviceId, persistedSession.deviceId]),
),
deviceType: normalizeCloudtentaclesDeviceType(
payload.deviceType ?? savedSource.deviceType ?? persistedSession.deviceType
payload.deviceType ?? savedSource.deviceType ?? persistedSession.deviceType,
),
};
}
}
export function hasCloudtentaclesCredentialContextChanged(
current: JsonObject = {},
next: JsonObject = {}
next: JsonObject = {},
) {
return (
String(current.baseUrl || "").trim() !==
String(next.baseUrl || "").trim() ||
String(current.username || "").trim() !==
String(next.username || "").trim() ||
String(current.phone || "").trim() !== String(next.phone || "").trim() ||
String(current.deviceId || "").trim() !==
String(next.deviceId || "").trim() ||
String(current.baseUrl || '').trim() !== String(next.baseUrl || '').trim() ||
String(current.username || '').trim() !== String(next.username || '').trim() ||
String(current.phone || '').trim() !== String(next.phone || '').trim() ||
String(current.deviceId || '').trim() !== String(next.deviceId || '').trim() ||
Number(current.deviceType || 0) !== Number(next.deviceType || 0)
);
)
}
File diff suppressed because it is too large Load Diff
@@ -1,11 +1,7 @@
import test from 'node:test'
import assert from 'node:assert/strict'
import {
mapAdminCloudtentaclesSession,
maskPhone,
maskSecret,
} from './mappers.js'
import { mapAdminCloudtentaclesSession, maskPhone, maskSecret } from './mappers.js'
test('maskSecret preserves edges while hiding middle characters', () => {
assert.equal(maskSecret('abcdef1234567890'), 'abcdef****567890')
@@ -2,44 +2,44 @@ import type { JsonObject } from '../../../../types/json.js'
import {
maskPhone as maskPhoneValue,
maskSecret as maskSecretValue,
} from "../../../../utils/masking.js";
} from '../../../../utils/masking.js'
import {
normalizeCloudtentaclesDeviceId,
normalizeCloudtentaclesDeviceType,
} from "../../../platforms/cloudtentacles/defaults.js";
} from '../../../platforms/cloudtentacles/defaults.js'
export function maskSecret(value: unknown) {
return maskSecretValue(value);
return maskSecretValue(value)
}
export function maskPhone(value: unknown) {
return maskPhoneValue(value, { maskShort: false });
return maskPhoneValue(value, { maskShort: false })
}
export function mapAdminCloudtentaclesSourceConfig(config: JsonObject = {}) {
return {
key: String(config.key || "").trim(),
label: String(config.label || "").trim(),
key: String(config.key || '').trim(),
label: String(config.label || '').trim(),
enabled: config.enabled !== false,
baseUrl: String(config.baseUrl || "").trim(),
username: String(config.username || "").trim(),
password: String(config.password || "").trim(),
phone: String(config.phone || "").trim(),
baseUrl: String(config.baseUrl || '').trim(),
username: String(config.username || '').trim(),
password: String(config.password || '').trim(),
phone: String(config.phone || '').trim(),
deviceId: normalizeCloudtentaclesDeviceId(config.deviceId),
deviceType: normalizeCloudtentaclesDeviceType(config.deviceType),
};
}
}
export function mapAdminCloudtentaclesSession(session: JsonObject = {}) {
return {
token: String(session.token || "").trim(),
token: String(session.token || '').trim(),
tokenMasked: maskSecret(session.token),
baseUrl: String(session.baseUrl || "").trim(),
username: String(session.username || "").trim(),
baseUrl: String(session.baseUrl || '').trim(),
username: String(session.username || '').trim(),
phoneMasked: maskPhone(session.phone),
loggedInAt: String(session.loggedInAt || "").trim(),
loggedInAt: String(session.loggedInAt || '').trim(),
deviceId: normalizeCloudtentaclesDeviceId(session.deviceId),
deviceType: normalizeCloudtentaclesDeviceType(session.deviceType),
hasToken: Boolean(String(session.token || "").trim()),
};
hasToken: Boolean(String(session.token || '').trim()),
}
}
@@ -1,96 +1,80 @@
import { getCloudtentaclesSourceByKey } from "../../../platforms/cloudtentacles/source-config-service.js";
import { getCloudtentaclesSessionStateByKey } from "../../../platforms/cloudtentacles/session-state-service.js";
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,
} from "../../../platforms/cloudtentacles/defaults.js";
import {
pickFirstNonEmpty,
resolveCloudtentaclesAdminContext,
} from "./context.js";
import { maskPhone, maskSecret } from "./mappers.js";
} from '../../../platforms/cloudtentacles/defaults.js'
import { pickFirstNonEmpty, resolveCloudtentaclesAdminContext } from './context.js'
import { maskPhone, maskSecret } from './mappers.js'
const DEFAULT_CLOUDTENTACLES_BASE_URL = "https://123.207.217.176";
const DEFAULT_CLOUDTENTACLES_BASE_URL = 'https://123.207.217.176'
function _resolveSourceKey(payload: JsonObject = {}) {
return String(payload.sourceKey || "").trim() || "default";
return String(payload.sourceKey || '').trim() || 'default'
}
export function resolveAdminCloudtentaclesCredentialPayload(
payload: JsonObject = {},
options: JsonObject = {}
options: JsonObject = {},
) {
const sourceKey = _resolveSourceKey(payload);
const savedSource = options.savedSource || getCloudtentaclesSourceByKey(sourceKey) || {};
const defaultBaseUrl = String(
options.defaultBaseUrl || DEFAULT_CLOUDTENTACLES_BASE_URL
).trim();
const sourceKey = _resolveSourceKey(payload)
const savedSource = options.savedSource || getCloudtentaclesSourceByKey(sourceKey) || {}
const defaultBaseUrl = String(options.defaultBaseUrl || DEFAULT_CLOUDTENTACLES_BASE_URL).trim()
return {
sourceKey,
baseUrl: pickFirstNonEmpty([
payload.baseUrl,
savedSource.baseUrl,
defaultBaseUrl,
]),
baseUrl: pickFirstNonEmpty([payload.baseUrl, savedSource.baseUrl, defaultBaseUrl]),
username: pickFirstNonEmpty([payload.username, savedSource.username]),
password: pickFirstNonEmpty([payload.password, savedSource.password]),
phone: pickFirstNonEmpty([payload.phone, savedSource.phone]),
deviceId: normalizeCloudtentaclesDeviceId(
pickFirstNonEmpty([payload.deviceId, savedSource.deviceId])
pickFirstNonEmpty([payload.deviceId, savedSource.deviceId]),
),
deviceType: normalizeCloudtentaclesDeviceType(
payload.deviceType ?? savedSource.deviceType
),
};
deviceType: normalizeCloudtentaclesDeviceType(payload.deviceType ?? savedSource.deviceType),
}
}
export function resolveAdminCloudtentaclesSessionPayload(
payload: JsonObject = {},
options: JsonObject = {}
options: JsonObject = {},
) {
const sourceKey = _resolveSourceKey(payload);
const savedSource = options.savedSource || getCloudtentaclesSourceByKey(sourceKey) || {};
const persistedSession = options.persistedSession ||
getCloudtentaclesSessionStateByKey(sourceKey) ||
{};
const sourceKey = _resolveSourceKey(payload)
const savedSource = options.savedSource || getCloudtentaclesSourceByKey(sourceKey) || {}
const persistedSession =
options.persistedSession || getCloudtentaclesSessionStateByKey(sourceKey) || {}
return resolveCloudtentaclesAdminContext(payload, {
savedSource,
persistedSession,
sourceKey,
defaultBaseUrl: options.defaultBaseUrl || DEFAULT_CLOUDTENTACLES_BASE_URL,
});
})
}
export function buildAdminCloudtentaclesPersistedSessionPayload(
session: JsonObject = {},
options: JsonObject = {}
options: JsonObject = {},
) {
return {
token: String(session.token || "").trim(),
baseUrl: String(session.baseUrl || "").trim(),
token: String(session.token || '').trim(),
baseUrl: String(session.baseUrl || '').trim(),
username: pickFirstNonEmpty([options.username, session.username]),
phone: pickFirstNonEmpty([options.phone, session.phone]),
loggedInAt: String(session.loggedInAt || "").trim(),
loggedInAt: String(session.loggedInAt || '').trim(),
deviceId: normalizeCloudtentaclesDeviceId(
pickFirstNonEmpty([options.deviceId, session.deviceId])
pickFirstNonEmpty([options.deviceId, session.deviceId]),
),
deviceType: normalizeCloudtentaclesDeviceType(
options.deviceType ?? session.deviceType
),
};
deviceType: normalizeCloudtentaclesDeviceType(options.deviceType ?? session.deviceType),
}
}
export function buildAdminCloudtentaclesSessionSummary(
session: JsonObject = {},
savedSession: JsonObject = {},
sourceKey = "default"
sourceKey = 'default',
) {
const permissions = Array.isArray(session.permissions)
? session.permissions
: [];
const permissions = Array.isArray(session.permissions) ? session.permissions : []
return {
sourceKey,
@@ -98,47 +82,39 @@ export function buildAdminCloudtentaclesSessionSummary(
permissionCount: permissions.length,
permissions,
persisted: Boolean(savedSession.token),
};
}
}
export function buildAdminCloudtentaclesLoginResult(
session: JsonObject = {},
savedSession: JsonObject = {},
sourceKey = "default"
sourceKey = 'default',
) {
return {
sourceKey,
baseUrl: String(session.baseUrl || "").trim(),
username: String(session.username || "").trim(),
baseUrl: String(session.baseUrl || '').trim(),
username: String(session.username || '').trim(),
phoneMasked: maskPhone(session.phone),
loggedInAt: String(session.loggedInAt || "").trim(),
responseMessage: String(session.responseMessage || "").trim(),
token: String(session.token || "").trim(),
session: buildAdminCloudtentaclesSessionSummary(
session,
savedSession,
sourceKey
),
loggedInAt: String(session.loggedInAt || '').trim(),
responseMessage: String(session.responseMessage || '').trim(),
token: String(session.token || '').trim(),
session: buildAdminCloudtentaclesSessionSummary(session, savedSession, sourceKey),
userInfo: session.userInfo,
asset: session.asset,
};
}
}
export function buildAdminCloudtentaclesValidateResult(
session: JsonObject = {},
savedSession: JsonObject = {},
sourceKey = "default"
sourceKey = 'default',
) {
return {
sourceKey,
baseUrl: String(session.baseUrl || "").trim(),
loggedInAt: String(session.loggedInAt || "").trim(),
session: buildAdminCloudtentaclesSessionSummary(
session,
savedSession,
sourceKey
),
baseUrl: String(session.baseUrl || '').trim(),
loggedInAt: String(session.loggedInAt || '').trim(),
session: buildAdminCloudtentaclesSessionSummary(session, savedSession, sourceKey),
userInfo: session.userInfo,
asset: session.asset,
};
}
}
@@ -2,22 +2,19 @@ import type { JsonObject } from '../../../../types/json.js'
import {
normalizeCloudtentaclesDeviceId,
normalizeCloudtentaclesDeviceType,
} from "../../../platforms/cloudtentacles/defaults.js";
} from '../../../platforms/cloudtentacles/defaults.js'
export function normalizeAdminCloudtentaclesSourceConfigPayload(
payload: JsonObject = {}
) {
const sourceKey =
String(payload.sourceKey || payload.key || "").trim() || "default";
export function normalizeAdminCloudtentaclesSourceConfigPayload(payload: JsonObject = {}) {
const sourceKey = String(payload.sourceKey || payload.key || '').trim() || 'default'
return {
key: sourceKey,
label: String(payload.label || "").trim(),
label: String(payload.label || '').trim(),
enabled: payload.enabled !== false,
baseUrl: String(payload.baseUrl || "").trim() || "https://123.207.217.176",
username: String(payload.username || "").trim(),
password: String(payload.password || "").trim(),
phone: String(payload.phone || "").trim(),
baseUrl: String(payload.baseUrl || '').trim() || 'https://123.207.217.176',
username: String(payload.username || '').trim(),
password: String(payload.password || '').trim(),
phone: String(payload.phone || '').trim(),
deviceId: normalizeCloudtentaclesDeviceId(payload.deviceId),
deviceType: normalizeCloudtentaclesDeviceType(payload.deviceType),
};
}
}
@@ -60,14 +60,18 @@ export async function listAdminKuaishouFeifeiProducts(payload: JsonObject = {})
page: Number(payload.page || 1) || 1,
perPage: Number(payload.perPage || payload.per_page || 20) || 20,
status: String(payload.status || 'on_sale').trim(),
supplyProductName: String(payload.supplyProductName || payload.supply_product_name || '').trim(),
supplyProductName: String(
payload.supplyProductName || payload.supply_product_name || '',
).trim(),
})
}
export async function syncAdminKuaishouFeifeiProductRules(payload: JsonObject = {}) {
const source = getAdminEditableKuaishouFeifeiConfig()
const status = String(payload.status || 'on_sale').trim() || 'on_sale'
const supplyProductName = String(payload.supplyProductName || payload.supply_product_name || '').trim()
const supplyProductName = String(
payload.supplyProductName || payload.supply_product_name || '',
).trim()
const products = await listAllKuaishouFeifeiProducts({
status,
supplyProductName,
@@ -185,10 +189,7 @@ function mapEffectiveKuaishouFeifeiConfig(config: ReturnType<typeof getKuaishouF
}
}
async function listAllKuaishouFeifeiProducts(input: {
status: string
supplyProductName: string
}) {
async function listAllKuaishouFeifeiProducts(input: { status: string; supplyProductName: string }) {
const perPage = 100
const firstPage = await listKuaishouFeifeiProducts({
page: 1,
@@ -14,16 +14,9 @@ import {
refreshKuaishouIndustryAccessToken,
} from '../../platforms/kuaishou-industry/token-service.js'
const SECRET_FIELDS = [
'appSecret',
'signSecret',
'messageSecret',
] as const
const SECRET_FIELDS = ['appSecret', 'signSecret', 'messageSecret'] as const
const SHOP_SECRET_FIELDS = [
'accessToken',
'refreshToken',
] as const
const SHOP_SECRET_FIELDS = ['accessToken', 'refreshToken'] as const
export function getAdminKuaishouIndustrySourceConfig() {
const config = getKuaishouIndustrySourceConfig()
@@ -38,15 +31,23 @@ export async function updateAdminKuaishouIndustrySourceConfig(payload: JsonObjec
const current = getKuaishouIndustrySourceConfig()
const saved = await saveKuaishouIndustrySourceConfig({
...current,
enabled: hasPayloadField(payload, 'enabled') ? payload.enabled !== false : current.enabled !== false,
enabled: hasPayloadField(payload, 'enabled')
? payload.enabled !== false
: current.enabled !== false,
baseUrl: readConfigString(payload, 'baseUrl', current.baseUrl),
authBaseUrl: readConfigString(payload, 'authBaseUrl', current.authBaseUrl),
redirectUri: readConfigString(payload, 'redirectUri', current.redirectUri, { allowBlank: true }),
scopes: normalizeScopeText(readConfigString(payload, 'scopes', current.scopes, { allowBlank: true })),
redirectUri: readConfigString(payload, 'redirectUri', current.redirectUri, {
allowBlank: true,
}),
scopes: normalizeScopeText(
readConfigString(payload, 'scopes', current.scopes, { allowBlank: true }),
),
authState: readConfigString(payload, 'authState', current.authState, { allowBlank: true }),
appKey: readConfigString(payload, 'appKey', current.appKey, { allowBlank: true }),
openId: readConfigString(payload, 'openId', current.openId, { allowBlank: true }),
grantedScopes: normalizeScopeText(readConfigString(payload, 'grantedScopes', current.grantedScopes, { allowBlank: true })),
grantedScopes: normalizeScopeText(
readConfigString(payload, 'grantedScopes', current.grantedScopes, { allowBlank: true }),
),
sellerId: readConfigString(payload, 'sellerId', current.sellerId, { allowBlank: true }),
provider: readConfigString(payload, 'provider', current.provider),
platform: readConfigString(payload, 'platform', current.platform),
@@ -245,33 +246,77 @@ function normalizeShopConfigPayload(
const payload = rawShop as JsonObject
const current = resolveCurrentShopConfig(payload, index, currentShops)
const sellerId = readConfigString(payload, 'sellerId', current?.sellerId || '', { allowBlank: true })
const shopId = readConfigString(payload, 'shopId', current?.shopId || sellerId, { allowBlank: true }) || sellerId
const shopName = readConfigString(payload, 'shopName', current?.shopName || '', { allowBlank: true })
const customShopName = readConfigString(payload, 'customShopName', current?.customShopName || '', { allowBlank: true })
const sellerId = readConfigString(payload, 'sellerId', current?.sellerId || '', {
allowBlank: true,
})
const shopId =
readConfigString(payload, 'shopId', current?.shopId || sellerId, { allowBlank: true }) ||
sellerId
const shopName = readConfigString(payload, 'shopName', current?.shopName || '', {
allowBlank: true,
})
const customShopName = readConfigString(
payload,
'customShopName',
current?.customShopName || '',
{ allowBlank: true },
)
const accessToken = readSecretString(payload, 'accessToken', current?.accessToken || '')
const refreshToken = readSecretString(payload, 'refreshToken', current?.refreshToken || '')
const openId = readConfigString(payload, 'openId', current?.openId || '', { allowBlank: true })
if (!sellerId && !shopId && !shopName && !customShopName && !accessToken && !refreshToken && !openId) {
if (
!sellerId &&
!shopId &&
!shopName &&
!customShopName &&
!accessToken &&
!refreshToken &&
!openId
) {
return null
}
return {
enabled: hasPayloadField(payload, 'enabled') ? payload.enabled !== false : current?.enabled !== false,
enabled: hasPayloadField(payload, 'enabled')
? payload.enabled !== false
: current?.enabled !== false,
sellerId,
shopId,
shopName,
customShopName,
authState: readConfigString(payload, 'authState', current?.authState || '', { allowBlank: true }),
authState: readConfigString(payload, 'authState', current?.authState || '', {
allowBlank: true,
}),
accessToken,
refreshToken,
accessTokenExpiresAt: readConfigString(payload, 'accessTokenExpiresAt', current?.accessTokenExpiresAt || '', { allowBlank: true }),
refreshTokenExpiresAt: readConfigString(payload, 'refreshTokenExpiresAt', current?.refreshTokenExpiresAt || '', { allowBlank: true }),
accessTokenExpiresAt: readConfigString(
payload,
'accessTokenExpiresAt',
current?.accessTokenExpiresAt || '',
{ allowBlank: true },
),
refreshTokenExpiresAt: readConfigString(
payload,
'refreshTokenExpiresAt',
current?.refreshTokenExpiresAt || '',
{ allowBlank: true },
),
openId,
grantedScopes: normalizeScopeText(readConfigString(payload, 'grantedScopes', current?.grantedScopes || '', { allowBlank: true })),
lastRefreshedAt: readConfigString(payload, 'lastRefreshedAt', current?.lastRefreshedAt || '', { allowBlank: true }),
lastRefreshError: readConfigString(payload, 'lastRefreshError', current?.lastRefreshError || '', { allowBlank: true }),
grantedScopes: normalizeScopeText(
readConfigString(payload, 'grantedScopes', current?.grantedScopes || '', {
allowBlank: true,
}),
),
lastRefreshedAt: readConfigString(payload, 'lastRefreshedAt', current?.lastRefreshedAt || '', {
allowBlank: true,
}),
lastRefreshError: readConfigString(
payload,
'lastRefreshError',
current?.lastRefreshError || '',
{ allowBlank: true },
),
...resolveShopSecretPatch(payload, current),
}
}
@@ -305,16 +350,14 @@ function resolveShopSecretPatch(
return patch
}
function readSecretString(
payload: JsonObject,
field: string,
fallback: string,
): string {
function readSecretString(payload: JsonObject, field: string, fallback: string): string {
const text = String(payload[field] || '').trim()
return text || fallback
}
function resolveAccessTokenStatus(config: Pick<KuaishouIndustrySourceConfig, 'accessToken' | 'accessTokenExpiresAt'>) {
function resolveAccessTokenStatus(
config: Pick<KuaishouIndustrySourceConfig, 'accessToken' | 'accessTokenExpiresAt'>,
) {
if (!config.accessToken) {
return {
status: 'missing',
@@ -94,23 +94,27 @@ function mapAdminNotificationConfig(config: JsonObject = {}) {
bark: {
enabled: bark.enabled !== false,
serverUrl: String(bark.serverUrl || 'https://api.day.app').trim(),
recipients: (Array.isArray(bark.recipients) ? bark.recipients : []).map((item: JsonObject) => ({
id: String(item.id || '').trim(),
name: String(item.name || '').trim(),
deviceKey: String(item.deviceKey || '').trim(),
deviceKeyMasked: maskSecret(item.deviceKey),
enabled: item.enabled !== false,
})),
recipients: (Array.isArray(bark.recipients) ? bark.recipients : []).map(
(item: JsonObject) => ({
id: String(item.id || '').trim(),
name: String(item.name || '').trim(),
deviceKey: String(item.deviceKey || '').trim(),
deviceKeyMasked: maskSecret(item.deviceKey),
enabled: item.enabled !== false,
}),
),
},
wpush: {
enabled: wpush.enabled !== false,
recipients: (Array.isArray(wpush.recipients) ? wpush.recipients : []).map((item: JsonObject) => ({
id: String(item.id || '').trim(),
name: String(item.name || '').trim(),
apiKey: String(item.apiKey || item.apikey || '').trim(),
apiKeyMasked: maskSecret(item.apiKey || item.apikey),
enabled: item.enabled !== false,
})),
recipients: (Array.isArray(wpush.recipients) ? wpush.recipients : []).map(
(item: JsonObject) => ({
id: String(item.id || '').trim(),
name: String(item.name || '').trim(),
apiKey: String(item.apiKey || item.apikey || '').trim(),
apiKeyMasked: maskSecret(item.apiKey || item.apikey),
enabled: item.enabled !== false,
}),
),
},
},
}
@@ -118,8 +122,7 @@ function mapAdminNotificationConfig(config: JsonObject = {}) {
function mapAdminScheduledJobsConfig(config: JsonObject = {}) {
const cloudtentaclesAccountMap = new Map(
listAdminCloudtentaclesMonitorAccounts()
.map((item) => [item.sourceKey, item]),
listAdminCloudtentaclesMonitorAccounts().map((item) => [item.sourceKey, item]),
)
return {
@@ -147,21 +150,23 @@ function listAdminCloudtentaclesMonitorAccounts() {
const sessionsConfig = getAllCloudtentaclesSessionStates()
const sessions: Record<string, JsonObject> = sessionsConfig.sessions || {}
return (Array.isArray(sourcesConfig.sources) ? sourcesConfig.sources : []).map((source) => {
const sourceKey = String(source.key || '').trim()
const session = sessions[sourceKey] || {}
const label = String(source.label || source.username || sourceKey).trim() || sourceKey
return (Array.isArray(sourcesConfig.sources) ? sourcesConfig.sources : [])
.map((source) => {
const sourceKey = String(source.key || '').trim()
const session = sessions[sourceKey] || {}
const label = String(source.label || source.username || sourceKey).trim() || sourceKey
return {
sourceKey,
label,
enabled: source.enabled !== false,
username: String(source.username || '').trim(),
phoneMasked: maskPhone(source.phone || session.phone),
hasToken: Boolean(String(session.token || '').trim()),
loggedInAt: String(session.loggedInAt || '').trim(),
}
}).filter((item) => item.sourceKey)
return {
sourceKey,
label,
enabled: source.enabled !== false,
username: String(source.username || '').trim(),
phoneMasked: maskPhone(source.phone || session.phone),
hasToken: Boolean(String(session.token || '').trim()),
loggedInAt: String(session.loggedInAt || '').trim(),
}
})
.filter((item) => item.sourceKey)
}
function mapScheduledJobCloudtentaclesAccounts(
@@ -193,30 +198,35 @@ function mapScheduledJobCloudtentaclesAccounts(
},
] as const
})
.filter(Boolean) as Array<readonly [string, {
sourceKey: string
label: string
enabled: boolean
assetThreshold: number
}]>,
.filter(Boolean) as Array<
readonly [
string,
{
sourceKey: string
label: string
enabled: boolean
assetThreshold: number
},
]
>,
)
// 读配置时合并全部 kuaishou-lewan 账号,避免前端/任务只看到历史 default。
const merged = Array.from(cloudtentaclesAccountMap.values()).map((option) => {
const sourceKey = String(option.sourceKey || '').trim()
const configured = configuredMap.get(sourceKey)
return {
sourceKey,
label: String(configured?.label || option.label || sourceKey).trim(),
enabled: configured
? configured.enabled !== false
: option.enabled !== false,
assetThreshold: normalizeNonNegativeNumber(
configured?.assetThreshold,
defaultAssetThreshold,
),
}
}).filter((item) => item.sourceKey)
const merged = Array.from(cloudtentaclesAccountMap.values())
.map((option) => {
const sourceKey = String(option.sourceKey || '').trim()
const configured = configuredMap.get(sourceKey)
return {
sourceKey,
label: String(configured?.label || option.label || sourceKey).trim(),
enabled: configured ? configured.enabled !== false : option.enabled !== false,
assetThreshold: normalizeNonNegativeNumber(
configured?.assetThreshold,
defaultAssetThreshold,
),
}
})
.filter((item) => item.sourceKey)
const mergedKeys = new Set(merged.map((item) => item.sourceKey))
for (const [sourceKey, configured] of configuredMap.entries()) {
@@ -1,8 +1,5 @@
import { buildClaimUrl, createTaskClaimToken } from '../claim/claim-service.js'
import {
maskCode as maskCodeValue,
maskPhone as maskPhoneValue,
} from '../../utils/masking.js'
import { maskCode as maskCodeValue, maskPhone as maskPhoneValue } from '../../utils/masking.js'
import type { TaskRow } from '../../types/repository/rows.js'
@@ -31,7 +28,9 @@ export function isRecoverableTaskSessionCloseError(error: ErrorLike | null | und
}
export function normalizeManualDispatchOutcome(value: unknown): 'delivered' | 'failed' {
const normalized = String(value || '').trim().toLowerCase()
const normalized = String(value || '')
.trim()
.toLowerCase()
if (normalized === 'failed') {
return 'failed'
@@ -25,18 +25,13 @@ import {
refreshFulfillmentRole,
returnFulfillmentNumber,
} from '../../fulfillment/executors/registry.js'
import {
isKuaishouCloudTask,
normalizeKuaishouCloudFlow,
} from './kuaishou-cloud-helpers.js'
import { isKuaishouCloudTask, normalizeKuaishouCloudFlow } from './kuaishou-cloud-helpers.js'
import type {
AdminEntityIdInput,
AdminViewerSessionInput,
} from '../../../types/admin/read-inputs.js'
import type {
AdminTaskKuaishouIndustryConsumeInput,
} from '../../../types/admin/write-inputs.js'
import type { AdminTaskKuaishouIndustryConsumeInput } from '../../../types/admin/write-inputs.js'
import type { AdminTaskActionResponse } from '../../../types/admin/write-models.js'
import type { KuaishouIndustryVoucherRow, TaskRow } from '../../../types/repository/rows.js'
@@ -443,8 +438,8 @@ export async function consumeAdminTaskKuaishouIndustryVoucher(
const taskContext = parseTaskContext(consumeTargetTask)
const hasCloudFulfillmentContext = Boolean(
taskContext.kuaishouCloudFulfillment &&
typeof taskContext.kuaishouCloudFulfillment === 'object' &&
!Array.isArray(taskContext.kuaishouCloudFulfillment),
typeof taskContext.kuaishouCloudFulfillment === 'object' &&
!Array.isArray(taskContext.kuaishouCloudFulfillment),
)
const flow = hasCloudFulfillmentContext
? normalizeKuaishouCloudFlow(taskContext.kuaishouCloudFulfillment)
@@ -491,7 +486,9 @@ export async function consumeAdminTaskKuaishouIndustryVoucher(
return { task: mapTaskActionPayload(updatedTask || consumeTargetTask) }
}
async function getRequiredIndustryVoucherForTask(task: TaskRow): Promise<KuaishouIndustryVoucherRow> {
async function getRequiredIndustryVoucherForTask(
task: TaskRow,
): Promise<KuaishouIndustryVoucherRow> {
const vouchers = await listKuaishouIndustryVouchersByTaskId(task.id)
const firstVoucher = vouchers[0]
if (firstVoucher) {
@@ -499,7 +496,9 @@ async function getRequiredIndustryVoucherForTask(task: TaskRow): Promise<Kuaisho
}
const taskContext = parseTaskContext(task)
const voucherContext = normalizeAdminTaskIndustryVoucherContext(taskContext.kuaishouIndustryVoucher)
const voucherContext = normalizeAdminTaskIndustryVoucherContext(
taskContext.kuaishouIndustryVoucher,
)
const voucherCode = String(voucherContext.voucherCode || voucherContext.eticketId || '').trim()
if (voucherCode) {
const voucher = await findKuaishouIndustryVoucherByCode(voucherCode, task.platform_order_id)
@@ -539,12 +538,12 @@ async function getRequiredIndustryVoucherForTask(task: TaskRow): Promise<Kuaisho
}
function normalizeAdminTaskIndustryVoucherContext(value: unknown): JsonObject {
return value && typeof value === 'object' && !Array.isArray(value)
? value as JsonObject
: {}
return value && typeof value === 'object' && !Array.isArray(value) ? (value as JsonObject) : {}
}
async function resolveIndustryVouchersForOrder(platformOrderId: string): Promise<KuaishouIndustryVoucherRow[]> {
async function resolveIndustryVouchersForOrder(
platformOrderId: string,
): Promise<KuaishouIndustryVoucherRow[]> {
const normalizedOid = String(platformOrderId || '').trim()
if (!normalizedOid) {
return []
@@ -52,7 +52,9 @@ export type PreparedKuaishouCloudBindResource = {
bindUrl: string
}
export function resolvePersistedCloudtentaclesContext(sourceKeys: unknown[]): CloudtentaclesContext {
export function resolvePersistedCloudtentaclesContext(
sourceKeys: unknown[],
): CloudtentaclesContext {
try {
return resolvePersistedCloudtentaclesContextBySourceKeys(sourceKeys)
} catch (error) {
@@ -4,14 +4,8 @@ import { createTaskEvent } from '../../../repositories/task-event-repo.js'
import { createHttpError } from '../../../utils/http.js'
import { nowIso } from '../../../utils/time.js'
import { TASK_STATUS } from '../../../domain/task-status.js'
import {
canViewerCloseTask,
createAdminViewerContext,
} from '../admin-read-shared-helpers.js'
import {
getRequiredTask,
mapTaskActionPayload,
} from '../admin-task-read-helpers.js'
import { canViewerCloseTask, createAdminViewerContext } from '../admin-read-shared-helpers.js'
import { getRequiredTask, mapTaskActionPayload } from '../admin-task-read-helpers.js'
import type {
AdminEntityIdInput,
@@ -62,16 +56,21 @@ export async function closeAdminTask(
})
}
await createTaskEvent(task.id, 'task_closed', {
closedBy: session
? {
userId: session.userId,
username: session.username,
role: session.role,
}
: null,
claimTokenClosed: claimTokenId > 0,
}, now)
await createTaskEvent(
task.id,
'task_closed',
{
closedBy: session
? {
userId: session.userId,
username: session.username,
role: session.role,
}
: null,
claimTokenClosed: claimTokenId > 0,
},
now,
)
return {
task: mapTaskActionPayload(updatedTask),