import { string } from 'alga-js' // Per-credential token cache: each custom DHL account (different OrderSource) gets // its own cached token. TTL of 50 minutes leaves a safety margin under DHL's // typical 1-hour token lifetime. const TOKEN_TTL_MS = 50 * 60 * 1000 const COOKIE_MAX_AGE_S = 50 * 60 const tokenCache = new Map() const cacheKey = (credential: any): string => `${credential?.dhlkey ?? ''}:${credential?.dhluser ?? ''}:${credential?.dhlurl ?? ''}` const getToken = async (credential: any) => { const config = { api: credential } return await $fetch(config.api.dhlurl+'/account/auth/ropc/v1/token', { method: 'POST', headers: { Accept: 'application/json', 'Content-Type': 'application/x-www-form-urlencoded' }, body: `grant_type=password&username=${string.urlEncode(config.api.dhluser)}&password=${string.urlEncode(config.api.dhlpass)}&client_id=${string.urlEncode(config.api.dhlkey)}&client_secret=${string.urlEncode(config.api.dhlsecret)}` }) } const persistToken = (event: any, credential: any, token: string) => { tokenCache.set(cacheKey(credential), { token, expiry: Date.now() + TOKEN_TTL_MS }) setCookie(event, 'logship_bdhtl2', token, { maxAge: COOKIE_MAX_AGE_S }) } const resolveToken = async (event: any, credential: any): Promise => { const key = cacheKey(credential) const cached = tokenCache.get(key) if (cached && cached.expiry > Date.now()) { return cached.token } const cookieToken = getCookie(event, 'logship_bdhtl2') ?? '' if (cookieToken !== '') { return cookieToken } const res = await getToken(credential) if (res?.access_token) { persistToken(event, credential, res.access_token) return res.access_token } return '' } export default async function dhlCustomHelper(event: any, credential: any, url: string, method: string = 'GET', body: any) { const config = { api: credential } let token = await resolveToken(event, credential) let options: any = {} if(body) { options = { ...options, body: body } } try { return await $fetch(config.api.dhlurl+'/'+url, { method: method, headers: { Accept: 'application/json', 'Content-Type': 'application/json', Authorization: 'Bearer ' + token }, ...options }) } catch(err: any) { // If it's a validation error (400), don't retry with new token - it won't help if(err?.statusCode === 400 || err?.status === 400) { console.error('[DHL Custom API Error] Validation error (400):', JSON.stringify(err?.data, null, 2)) throw err } // Invalidate cache: token may have been revoked even though our TTL says it's good. tokenCache.delete(cacheKey(credential)) const res2 = await getToken(credential) if(res2?.access_token) { token = res2.access_token persistToken(event, credential, token) } return await $fetch(config.api.dhlurl+'/'+url, { method: method, headers: { Accept: 'application/json', 'Content-Type': 'application/json', Authorization: 'Bearer ' + token }, ...options }) } }