76 lines
2.0 KiB
TypeScript
76 lines
2.0 KiB
TypeScript
import { buildClaimUrl, createTaskClaimToken } from '../claim/claim-service.js'
|
|
import {
|
|
maskCode as maskCodeValue,
|
|
maskPhone as maskPhoneValue,
|
|
} from '../../utils/masking.js'
|
|
|
|
import type { TaskRow } from '../../types/repository/rows.js'
|
|
|
|
type TaskClaimLink = {
|
|
token: string
|
|
expiredAt: string | null
|
|
claimUrl: string
|
|
}
|
|
|
|
type ErrorLike = {
|
|
errorCode?: string
|
|
code?: string
|
|
}
|
|
|
|
export function maskPhone(value: unknown): string {
|
|
return maskPhoneValue(value)
|
|
}
|
|
|
|
export function maskCode(value: unknown): string {
|
|
return maskCodeValue(value)
|
|
}
|
|
|
|
export function isRecoverableTaskSessionCloseError(error: ErrorLike | null | undefined): boolean {
|
|
const errorCode = String(error?.errorCode || error?.code || '').trim()
|
|
return errorCode === 'session_not_found' || errorCode === 'session_closed'
|
|
}
|
|
|
|
export function normalizeManualDispatchOutcome(value: unknown): 'delivered' | 'failed' {
|
|
const normalized = String(value || '').trim().toLowerCase()
|
|
|
|
if (normalized === 'failed') {
|
|
return 'failed'
|
|
}
|
|
|
|
return 'delivered'
|
|
}
|
|
|
|
export function getTaskClaimExpiresAt(task: Partial<TaskRow> | null | undefined): string | null {
|
|
return task?.claim_expires_at || task?.primary_claim_expires_at || null
|
|
}
|
|
|
|
export async function ensureTaskClaimLink(task: TaskRow): Promise<TaskClaimLink> {
|
|
const tokenStatus = String(task?.primary_claim_token_status || '').trim()
|
|
const token = String(task?.primary_claim_token || task?.claim_token || '').trim()
|
|
const expiredAt = getTaskClaimExpiresAt(task)
|
|
|
|
if (tokenStatus === 'active' && token && !isClaimExpired(expiredAt)) {
|
|
return {
|
|
token,
|
|
expiredAt,
|
|
claimUrl: buildClaimUrl(token),
|
|
}
|
|
}
|
|
|
|
const claimToken = await createTaskClaimToken(task.id)
|
|
return {
|
|
token: claimToken.token,
|
|
expiredAt: claimToken.expired_at,
|
|
claimUrl: claimToken.claimUrl,
|
|
}
|
|
}
|
|
|
|
function isClaimExpired(expiredAt: string | null): boolean {
|
|
if (!expiredAt) {
|
|
return false
|
|
}
|
|
|
|
const timestamp = new Date(expiredAt).getTime()
|
|
return Number.isFinite(timestamp) && timestamp <= Date.now()
|
|
}
|