cloudtentacles 增加登陆后持久化, 调试ok
This commit is contained in:
@@ -0,0 +1,174 @@
|
||||
// @ts-check
|
||||
|
||||
import { createHttpError } from '../../../utils/http.js'
|
||||
import { cloudtentaclesRequest } from './http-client.js'
|
||||
import { resolveCloudtentaclesConfig } from './shared.js'
|
||||
|
||||
export async function getCloudtentaclesAsset(payload = {}) {
|
||||
const token = requireToken(payload.token, 'cloudtentacles 余额查询缺少 token', 'cloudtentacles_asset_missing_token')
|
||||
const config = resolveCloudtentaclesConfig(payload)
|
||||
|
||||
const result = await cloudtentaclesRequest(config.assetPath, {
|
||||
...config,
|
||||
method: 'GET',
|
||||
token,
|
||||
contentType: 'application/json',
|
||||
businessErrorStatusCode: 401,
|
||||
businessErrorCode: 'cloudtentacles_asset_failed',
|
||||
})
|
||||
|
||||
return {
|
||||
baseUrl: config.baseUrl,
|
||||
asset: Number(result.payload?.data || 0),
|
||||
raw: result.payload?.data ?? null,
|
||||
}
|
||||
}
|
||||
|
||||
export async function getCloudtentaclesCategories(payload = {}) {
|
||||
const token = requireToken(payload.token, 'cloudtentacles 分类查询缺少 token', 'cloudtentacles_categories_missing_token')
|
||||
const config = resolveCloudtentaclesConfig(payload)
|
||||
|
||||
const result = await cloudtentaclesRequest(config.categoriesPath, {
|
||||
...config,
|
||||
method: 'GET',
|
||||
token,
|
||||
contentType: 'application/json',
|
||||
businessErrorStatusCode: 401,
|
||||
businessErrorCode: 'cloudtentacles_categories_failed',
|
||||
})
|
||||
|
||||
const items = Array.isArray(result.payload?.data) ? result.payload.data.map(mapCategoryItem) : []
|
||||
|
||||
return {
|
||||
baseUrl: config.baseUrl,
|
||||
itemCount: items.length,
|
||||
items,
|
||||
rawItems: Array.isArray(result.payload?.data) ? result.payload.data : [],
|
||||
}
|
||||
}
|
||||
|
||||
export async function listCloudtentaclesSku(payload = {}) {
|
||||
const token = requireToken(payload.token, 'cloudtentacles SKU 列表查询缺少 token', 'cloudtentacles_sku_list_missing_token')
|
||||
const config = resolveCloudtentaclesConfig(payload)
|
||||
|
||||
const result = await cloudtentaclesRequest(config.skuListPath, {
|
||||
...config,
|
||||
method: 'GET',
|
||||
token,
|
||||
contentType: 'application/json',
|
||||
businessErrorStatusCode: 401,
|
||||
businessErrorCode: 'cloudtentacles_sku_list_failed',
|
||||
})
|
||||
|
||||
const items = Array.isArray(result.payload?.data) ? result.payload.data.map(mapSkuItem) : []
|
||||
|
||||
return {
|
||||
baseUrl: config.baseUrl,
|
||||
itemCount: items.length,
|
||||
items,
|
||||
rawItems: Array.isArray(result.payload?.data) ? result.payload.data : [],
|
||||
}
|
||||
}
|
||||
|
||||
export async function buyCloudtentaclesSku(payload = {}) {
|
||||
const token = requireToken(payload.token, 'cloudtentacles 购买 SKU 缺少 token', 'cloudtentacles_sku_buy_missing_token')
|
||||
const skuId = requireId(payload.id, 'cloudtentacles 购买 SKU 缺少商品 id', 'cloudtentacles_sku_buy_missing_id')
|
||||
const count = requireCount(payload.count)
|
||||
const config = resolveCloudtentaclesConfig(payload)
|
||||
|
||||
const result = await cloudtentaclesRequest(config.skuBuyPath, {
|
||||
...config,
|
||||
method: 'POST',
|
||||
token,
|
||||
body: {
|
||||
id: skuId,
|
||||
count,
|
||||
},
|
||||
businessErrorStatusCode: 401,
|
||||
businessErrorCode: 'cloudtentacles_sku_buy_failed',
|
||||
})
|
||||
|
||||
return {
|
||||
baseUrl: config.baseUrl,
|
||||
id: skuId,
|
||||
count,
|
||||
responseMessage: String(result.payload?.message || result.payload?.msg || 'success'),
|
||||
}
|
||||
}
|
||||
|
||||
function mapCategoryItem(item) {
|
||||
const source = isPlainObject(item) ? item : {}
|
||||
|
||||
return {
|
||||
id: Number(source.id || 0),
|
||||
name: String(source.name || '').trim(),
|
||||
supplierTag: String(source.supplier_tag || '').trim(),
|
||||
description: String(source.description || '').trim(),
|
||||
notes: String(source.notes || '').trim(),
|
||||
expire: Number(source.expire || 0),
|
||||
sendType: Number(source.send_type || 0),
|
||||
exchangeUrl: String(source.exchange_url || '').trim(),
|
||||
createdAt: String(source.c_time || '').trim(),
|
||||
updatedAt: String(source.l_update_time || '').trim(),
|
||||
raw: source,
|
||||
}
|
||||
}
|
||||
|
||||
function mapSkuItem(item) {
|
||||
const source = isPlainObject(item) ? item : {}
|
||||
|
||||
return {
|
||||
id: Number(source.id || 0),
|
||||
categoriesId: Number(source.categories_id || 0),
|
||||
name: String(source.name || '').trim(),
|
||||
description: String(source.desc || '').trim(),
|
||||
image: String(source.image || '').trim(),
|
||||
inventory: Number(source.inventory || 0),
|
||||
price: Number(source.price || 0),
|
||||
listingTime: String(source.listing_time || '').trim(),
|
||||
delistingTime: String(source.delisting_time || '').trim(),
|
||||
buyLimitMin: Number(source.buy_limit_min || 0),
|
||||
buyLimitMax: Number(source.buy_limit_max || 0),
|
||||
raw: source,
|
||||
}
|
||||
}
|
||||
|
||||
function requireToken(value, message, errorCode) {
|
||||
const token = String(value || '').trim()
|
||||
if (!token) {
|
||||
throw createHttpError(message, {
|
||||
statusCode: 400,
|
||||
errorCode,
|
||||
})
|
||||
}
|
||||
|
||||
return token
|
||||
}
|
||||
|
||||
function requireId(value, message, errorCode) {
|
||||
const id = Number(value)
|
||||
if (!Number.isInteger(id) || id <= 0) {
|
||||
throw createHttpError(message, {
|
||||
statusCode: 400,
|
||||
errorCode,
|
||||
})
|
||||
}
|
||||
|
||||
return id
|
||||
}
|
||||
|
||||
function requireCount(value) {
|
||||
const count = Number(value)
|
||||
if (!Number.isInteger(count) || count <= 0) {
|
||||
throw createHttpError('cloudtentacles 购买数量无效', {
|
||||
statusCode: 400,
|
||||
errorCode: 'cloudtentacles_sku_buy_invalid_count',
|
||||
})
|
||||
}
|
||||
|
||||
return count
|
||||
}
|
||||
|
||||
function isPlainObject(value) {
|
||||
return Boolean(value) && typeof value === 'object' && !Array.isArray(value)
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
// @ts-check
|
||||
|
||||
import { createHttpError } from '../../../utils/http.js'
|
||||
import { cloudtentaclesRequest } from './http-client.js'
|
||||
import { resolveCloudtentaclesConfig } from './shared.js'
|
||||
|
||||
export async function getCloudtentaclesKnapsack(payload = {}) {
|
||||
const token = String(payload.token || '').trim()
|
||||
if (!token) {
|
||||
throw createHttpError('cloudtentacles 背包查询缺少 token', {
|
||||
statusCode: 400,
|
||||
errorCode: 'cloudtentacles_knapsack_missing_token',
|
||||
})
|
||||
}
|
||||
|
||||
const config = resolveCloudtentaclesConfig(payload)
|
||||
const result = await cloudtentaclesRequest(config.knapsackPath, {
|
||||
...config,
|
||||
method: 'GET',
|
||||
token,
|
||||
contentType: 'application/json',
|
||||
businessErrorStatusCode: 401,
|
||||
businessErrorCode: 'cloudtentacles_knapsack_failed',
|
||||
})
|
||||
|
||||
const items = Array.isArray(result.payload?.data) ? result.payload.data.map(mapKnapsackItem) : []
|
||||
|
||||
return {
|
||||
baseUrl: config.baseUrl,
|
||||
itemCount: items.length,
|
||||
items,
|
||||
rawItems: Array.isArray(result.payload?.data) ? result.payload.data : [],
|
||||
}
|
||||
}
|
||||
|
||||
function mapKnapsackItem(item) {
|
||||
const source = isPlainObject(item) ? item : {}
|
||||
|
||||
return {
|
||||
id: Number(source.id || 0),
|
||||
name: String(source.name || '').trim(),
|
||||
count: Number(source.count || 0),
|
||||
image: String(source.image || '').trim(),
|
||||
categoriesId: Number(source.categories_id || 0),
|
||||
listingTime: String(source.listing_time || '').trim(),
|
||||
delistingTime: String(source.delisting_time || '').trim(),
|
||||
raw: source,
|
||||
}
|
||||
}
|
||||
|
||||
function isPlainObject(value) {
|
||||
return Boolean(value) && typeof value === 'object' && !Array.isArray(value)
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
// @ts-check
|
||||
|
||||
import fs from 'node:fs'
|
||||
import path from 'node:path'
|
||||
|
||||
import { PROJECT_ROOT } from '../../../config/runtime.js'
|
||||
|
||||
const CLOUDTENTACLES_SESSION_FILE_PATH = path.join(PROJECT_ROOT, 'data', 'cloudtentacles-session.json')
|
||||
|
||||
export function getCloudtentaclesSessionFilePath() {
|
||||
return CLOUDTENTACLES_SESSION_FILE_PATH
|
||||
}
|
||||
|
||||
export function getCloudtentaclesSessionState() {
|
||||
return loadCloudtentaclesSessionStateFromFile()
|
||||
}
|
||||
|
||||
export function saveCloudtentaclesSessionState(rawValue) {
|
||||
const normalized = normalizeCloudtentaclesSessionState(rawValue)
|
||||
fs.mkdirSync(path.dirname(CLOUDTENTACLES_SESSION_FILE_PATH), { recursive: true })
|
||||
fs.writeFileSync(CLOUDTENTACLES_SESSION_FILE_PATH, `${JSON.stringify(normalized, null, 2)}\n`, 'utf8')
|
||||
return normalized
|
||||
}
|
||||
|
||||
export function clearCloudtentaclesSessionState() {
|
||||
const cleared = createDefaultCloudtentaclesSessionState()
|
||||
saveCloudtentaclesSessionState(cleared)
|
||||
return cleared
|
||||
}
|
||||
|
||||
function loadCloudtentaclesSessionStateFromFile() {
|
||||
if (!fs.existsSync(CLOUDTENTACLES_SESSION_FILE_PATH)) {
|
||||
return createDefaultCloudtentaclesSessionState()
|
||||
}
|
||||
|
||||
try {
|
||||
const rawText = fs.readFileSync(CLOUDTENTACLES_SESSION_FILE_PATH, 'utf8')
|
||||
return normalizeCloudtentaclesSessionState(JSON.parse(rawText))
|
||||
} catch {
|
||||
return createDefaultCloudtentaclesSessionState()
|
||||
}
|
||||
}
|
||||
|
||||
function normalizeCloudtentaclesSessionState(rawValue) {
|
||||
const source = isPlainObject(rawValue) ? rawValue : {}
|
||||
|
||||
return {
|
||||
token: String(source.token || '').trim(),
|
||||
baseUrl: String(source.baseUrl || '').trim(),
|
||||
username: String(source.username || '').trim(),
|
||||
phone: String(source.phone || '').trim(),
|
||||
loggedInAt: String(source.loggedInAt || '').trim(),
|
||||
deviceId: String(source.deviceId || '-').trim() || '-',
|
||||
deviceType: normalizeInteger(source.deviceType, 0),
|
||||
}
|
||||
}
|
||||
|
||||
function createDefaultCloudtentaclesSessionState() {
|
||||
return {
|
||||
token: '',
|
||||
baseUrl: '',
|
||||
username: '',
|
||||
phone: '',
|
||||
loggedInAt: '',
|
||||
deviceId: '-',
|
||||
deviceType: 0,
|
||||
}
|
||||
}
|
||||
|
||||
function normalizeInteger(value, fallback) {
|
||||
const parsed = Number(value)
|
||||
return Number.isInteger(parsed) ? parsed : fallback
|
||||
}
|
||||
|
||||
function isPlainObject(value) {
|
||||
return Object.prototype.toString.call(value) === '[object Object]'
|
||||
}
|
||||
@@ -14,6 +14,16 @@ export function resolveCloudtentaclesConfig(overrides = {}) {
|
||||
userInfoPath: '/user/info',
|
||||
assetPath: '/user/get_asset',
|
||||
permissionPath: '/user/get_permission',
|
||||
categoriesPath: '/categories/get',
|
||||
skuListPath: '/sku/list',
|
||||
skuBuyPath: '/sku/buy',
|
||||
knapsackPath: '/user/get_knapsack',
|
||||
vnListPath: '/vn/list',
|
||||
vnAppointPath: '/vn/appoint',
|
||||
vnGenerateLoginCodePath: '/vn/generate_login_code',
|
||||
vnVerifCodePath: '/public/vn_verif_code',
|
||||
vnVerifyLoginCodePath: '/vn/verify_login_code',
|
||||
vnBindUrlPath: '/vn/bind_url',
|
||||
publicKeyPem: '',
|
||||
clientSource: 'ct-client',
|
||||
deviceId: '-',
|
||||
@@ -28,6 +38,22 @@ export function resolveCloudtentaclesConfig(overrides = {}) {
|
||||
userInfoPath: normalizePath(overrides.userInfoPath || baseConfig.userInfoPath, '/user/info'),
|
||||
assetPath: normalizePath(overrides.assetPath || baseConfig.assetPath, '/user/get_asset'),
|
||||
permissionPath: normalizePath(overrides.permissionPath || baseConfig.permissionPath, '/user/get_permission'),
|
||||
categoriesPath: normalizePath(overrides.categoriesPath || baseConfig.categoriesPath, '/categories/get'),
|
||||
skuListPath: normalizePath(overrides.skuListPath || baseConfig.skuListPath, '/sku/list'),
|
||||
skuBuyPath: normalizePath(overrides.skuBuyPath || baseConfig.skuBuyPath, '/sku/buy'),
|
||||
knapsackPath: normalizePath(overrides.knapsackPath || baseConfig.knapsackPath, '/user/get_knapsack'),
|
||||
vnListPath: normalizePath(overrides.vnListPath || baseConfig.vnListPath, '/vn/list'),
|
||||
vnAppointPath: normalizePath(overrides.vnAppointPath || baseConfig.vnAppointPath, '/vn/appoint'),
|
||||
vnGenerateLoginCodePath: normalizePath(
|
||||
overrides.vnGenerateLoginCodePath || baseConfig.vnGenerateLoginCodePath,
|
||||
'/vn/generate_login_code',
|
||||
),
|
||||
vnVerifCodePath: normalizePath(overrides.vnVerifCodePath || baseConfig.vnVerifCodePath, '/public/vn_verif_code'),
|
||||
vnVerifyLoginCodePath: normalizePath(
|
||||
overrides.vnVerifyLoginCodePath || baseConfig.vnVerifyLoginCodePath,
|
||||
'/vn/verify_login_code',
|
||||
),
|
||||
vnBindUrlPath: normalizePath(overrides.vnBindUrlPath || baseConfig.vnBindUrlPath, '/vn/bind_url'),
|
||||
publicKeyPem: normalizePem(overrides.publicKeyPem || baseConfig.publicKeyPem),
|
||||
clientSource: String(overrides.clientSource || baseConfig.clientSource || 'ct-client').trim() || 'ct-client',
|
||||
deviceId: String(overrides.deviceId ?? baseConfig.deviceId ?? '-').trim() || '-',
|
||||
|
||||
@@ -0,0 +1,222 @@
|
||||
// @ts-check
|
||||
|
||||
import { createHttpError } from '../../../utils/http.js'
|
||||
import { cloudtentaclesRequest } from './http-client.js'
|
||||
import { resolveCloudtentaclesConfig } from './shared.js'
|
||||
|
||||
export async function listCloudtentaclesVirtualNumbers(payload = {}) {
|
||||
const token = requireToken(payload.token, 'cloudtentacles 虚拟号列表缺少 token', 'cloudtentacles_vn_list_missing_token')
|
||||
const key = requireKey(payload.key, 'cloudtentacles 虚拟号列表缺少 key', 'cloudtentacles_vn_list_missing_key')
|
||||
const config = resolveCloudtentaclesConfig(payload)
|
||||
|
||||
const result = await cloudtentaclesRequest(config.vnListPath, {
|
||||
...config,
|
||||
method: 'POST',
|
||||
token,
|
||||
body: { key },
|
||||
businessErrorStatusCode: 401,
|
||||
businessErrorCode: 'cloudtentacles_vn_list_failed',
|
||||
})
|
||||
|
||||
const items = Array.isArray(result.payload?.data) ? result.payload.data.map(mapVirtualNumberItem) : []
|
||||
|
||||
return {
|
||||
baseUrl: config.baseUrl,
|
||||
key,
|
||||
itemCount: items.length,
|
||||
items,
|
||||
rawItems: Array.isArray(result.payload?.data) ? result.payload.data : [],
|
||||
}
|
||||
}
|
||||
|
||||
export async function appointCloudtentaclesVirtualNumber(payload = {}) {
|
||||
const token = requireToken(payload.token, 'cloudtentacles 申请虚拟号缺少 token', 'cloudtentacles_vn_appoint_missing_token')
|
||||
const key = requireKey(payload.key, 'cloudtentacles 申请虚拟号缺少 key', 'cloudtentacles_vn_appoint_missing_key')
|
||||
const config = resolveCloudtentaclesConfig(payload)
|
||||
|
||||
const result = await cloudtentaclesRequest(config.vnAppointPath, {
|
||||
...config,
|
||||
method: 'POST',
|
||||
token,
|
||||
body: { key },
|
||||
businessErrorStatusCode: 401,
|
||||
businessErrorCode: 'cloudtentacles_vn_appoint_failed',
|
||||
})
|
||||
|
||||
return {
|
||||
baseUrl: config.baseUrl,
|
||||
key,
|
||||
item: mapVirtualNumberItem(result.payload?.data),
|
||||
rawItem: isPlainObject(result.payload?.data) ? result.payload.data : {},
|
||||
}
|
||||
}
|
||||
|
||||
export async function generateCloudtentaclesLoginCode(payload = {}) {
|
||||
const token = requireToken(payload.token, 'cloudtentacles 生成登录码缺少 token', 'cloudtentacles_vn_generate_code_missing_token')
|
||||
const key = requireKey(payload.key, 'cloudtentacles 生成登录码缺少 key', 'cloudtentacles_vn_generate_code_missing_key')
|
||||
const id = requireId(payload.id, 'cloudtentacles 生成登录码缺少 id', 'cloudtentacles_vn_generate_code_missing_id')
|
||||
const config = resolveCloudtentaclesConfig(payload)
|
||||
|
||||
const result = await cloudtentaclesRequest(config.vnGenerateLoginCodePath, {
|
||||
...config,
|
||||
method: 'POST',
|
||||
token,
|
||||
body: { key, id },
|
||||
businessErrorStatusCode: 401,
|
||||
businessErrorCode: 'cloudtentacles_vn_generate_code_failed',
|
||||
})
|
||||
|
||||
return {
|
||||
baseUrl: config.baseUrl,
|
||||
key,
|
||||
id,
|
||||
responseMessage: String(result.payload?.message || result.payload?.msg || 'success'),
|
||||
}
|
||||
}
|
||||
|
||||
export async function fetchCloudtentaclesVirtualNumberCode(payload = {}) {
|
||||
const token = requireToken(payload.token, 'cloudtentacles 获取验证码缺少 token', 'cloudtentacles_vn_verif_code_missing_token')
|
||||
const key = requireKey(payload.key, 'cloudtentacles 获取验证码缺少 key', 'cloudtentacles_vn_verif_code_missing_key')
|
||||
const phone = String(payload.phone || '').trim()
|
||||
if (!phone) {
|
||||
throw createHttpError('cloudtentacles 获取验证码缺少手机号', {
|
||||
statusCode: 400,
|
||||
errorCode: 'cloudtentacles_vn_verif_code_missing_phone',
|
||||
})
|
||||
}
|
||||
|
||||
const config = resolveCloudtentaclesConfig(payload)
|
||||
const result = await cloudtentaclesRequest(config.vnVerifCodePath, {
|
||||
...config,
|
||||
method: 'POST',
|
||||
token,
|
||||
body: { key, phone },
|
||||
businessErrorStatusCode: 401,
|
||||
businessErrorCode: 'cloudtentacles_vn_verif_code_failed',
|
||||
})
|
||||
|
||||
return {
|
||||
baseUrl: config.baseUrl,
|
||||
key,
|
||||
phone,
|
||||
code: String(result.payload?.data || '').trim(),
|
||||
responseMessage: String(result.payload?.message || result.payload?.msg || 'success'),
|
||||
}
|
||||
}
|
||||
|
||||
export async function verifyCloudtentaclesLoginCode(payload = {}) {
|
||||
const token = requireToken(payload.token, 'cloudtentacles 校验登录码缺少 token', 'cloudtentacles_vn_verify_code_missing_token')
|
||||
const key = requireKey(payload.key, 'cloudtentacles 校验登录码缺少 key', 'cloudtentacles_vn_verify_code_missing_key')
|
||||
const id = requireId(payload.id, 'cloudtentacles 校验登录码缺少 id', 'cloudtentacles_vn_verify_code_missing_id')
|
||||
const code = String(payload.code || '').trim()
|
||||
if (!code) {
|
||||
throw createHttpError('cloudtentacles 校验登录码缺少验证码', {
|
||||
statusCode: 400,
|
||||
errorCode: 'cloudtentacles_vn_verify_code_missing_code',
|
||||
})
|
||||
}
|
||||
|
||||
const config = resolveCloudtentaclesConfig(payload)
|
||||
const result = await cloudtentaclesRequest(config.vnVerifyLoginCodePath, {
|
||||
...config,
|
||||
method: 'POST',
|
||||
token,
|
||||
body: { key, id, code },
|
||||
businessErrorStatusCode: 401,
|
||||
businessErrorCode: 'cloudtentacles_vn_verify_code_failed',
|
||||
})
|
||||
|
||||
return {
|
||||
baseUrl: config.baseUrl,
|
||||
key,
|
||||
id,
|
||||
code,
|
||||
responseMessage: String(result.payload?.message || result.payload?.msg || 'success'),
|
||||
}
|
||||
}
|
||||
|
||||
export async function getCloudtentaclesBindUrl(payload = {}) {
|
||||
const token = requireToken(payload.token, 'cloudtentacles 获取兑换链接缺少 token', 'cloudtentacles_vn_bind_url_missing_token')
|
||||
const key = requireKey(payload.key, 'cloudtentacles 获取兑换链接缺少 key', 'cloudtentacles_vn_bind_url_missing_key')
|
||||
const id = requireId(payload.id, 'cloudtentacles 获取兑换链接缺少 id', 'cloudtentacles_vn_bind_url_missing_id')
|
||||
const config = resolveCloudtentaclesConfig(payload)
|
||||
|
||||
const result = await cloudtentaclesRequest(config.vnBindUrlPath, {
|
||||
...config,
|
||||
method: 'POST',
|
||||
token,
|
||||
body: { id, key },
|
||||
businessErrorStatusCode: 401,
|
||||
businessErrorCode: 'cloudtentacles_vn_bind_url_failed',
|
||||
})
|
||||
|
||||
return {
|
||||
baseUrl: config.baseUrl,
|
||||
key,
|
||||
id,
|
||||
bindUrl: String(result.payload?.data || '').trim(),
|
||||
responseMessage: String(result.payload?.message || result.payload?.msg || 'success'),
|
||||
}
|
||||
}
|
||||
|
||||
function mapVirtualNumberItem(item) {
|
||||
const source = isPlainObject(item) ? item : {}
|
||||
const bindInfoText = String(source.bind_info || '').trim()
|
||||
|
||||
return {
|
||||
id: Number(source.id || 0),
|
||||
phone: String(source.phone || '').trim(),
|
||||
status: Number(source.status || 0),
|
||||
countTime: Number(source.count_time || 0),
|
||||
bindInfo: tryParseJson(bindInfoText) || bindInfoText || null,
|
||||
raw: source,
|
||||
}
|
||||
}
|
||||
|
||||
function requireToken(value, message, errorCode) {
|
||||
const token = String(value || '').trim()
|
||||
if (!token) {
|
||||
throw createHttpError(message, {
|
||||
statusCode: 400,
|
||||
errorCode,
|
||||
})
|
||||
}
|
||||
|
||||
return token
|
||||
}
|
||||
|
||||
function requireKey(value, message, errorCode) {
|
||||
const key = String(value || '').trim()
|
||||
if (!key) {
|
||||
throw createHttpError(message, {
|
||||
statusCode: 400,
|
||||
errorCode,
|
||||
})
|
||||
}
|
||||
|
||||
return key
|
||||
}
|
||||
|
||||
function requireId(value, message, errorCode) {
|
||||
const id = Number(value)
|
||||
if (!Number.isInteger(id) || id <= 0) {
|
||||
throw createHttpError(message, {
|
||||
statusCode: 400,
|
||||
errorCode,
|
||||
})
|
||||
}
|
||||
|
||||
return id
|
||||
}
|
||||
|
||||
function tryParseJson(text) {
|
||||
try {
|
||||
return JSON.parse(text)
|
||||
} catch {
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
function isPlainObject(value) {
|
||||
return Boolean(value) && typeof value === 'object' && !Array.isArray(value)
|
||||
}
|
||||
Reference in New Issue
Block a user