(()=>{ 'use strict'; const READ_RPCS=new Set(['sun_my_workspaces','sun_fetch_app_state','sun_is_platform_admin','caterium_trial_demo_status']); function create({upstream,proxy,timeout=7000,fallbackTimeout=4000}){ const origin=new URL(upstream).origin; return async function(input,init={}){ const original=new Request(input,init),url=new URL(original.url),isBackend=url.origin===origin; const read=original.method==='GET'||original.method==='HEAD'||(original.method==='POST'&&url.pathname.startsWith('/rest/v1/rpc/')&&READ_RPCS.has(url.pathname.slice('/rest/v1/rpc/'.length))); const passwordLogin=original.method==='POST'&&url.pathname==='/auth/v1/token'&&url.searchParams.get('grant_type')==='password'; const safeFallback=isBackend&&(read||passwordLogin); const expectJson=original.method!=='HEAD'&&(passwordLogin||url.pathname.startsWith('/rest/v1/rpc/')||(read&&(url.pathname.startsWith('/rest/v1/')||url.pathname.startsWith('/auth/v1/')))); async function attempt(target,limit){ const controller=new AbortController(),abort=()=>controller.abort(original.signal.reason); if(original.signal.aborted)abort();else original.signal.addEventListener('abort',abort,{once:true}); const timer=setTimeout(()=>controller.abort(),limit); try{ const response=await fetch(new Request(target,original.clone()),{signal:controller.signal}); if(expectJson&&response.ok&&response.status!==204){ const text=await response.clone().text(); try{if(!text.trim()||!response.headers.get('content-type')?.includes('json'))throw new Error();JSON.parse(text)} catch(_){throw new Error('Сервис вернул пустой или некорректный ответ. Повторите загрузку.')} } return response; }finally{clearTimeout(timer);original.signal.removeEventListener('abort',abort)} } try{ const response=await attempt(isBackend?proxy+url.pathname+url.search:original.url,timeout); if(!safeFallback||response.status<500)return response; }catch(error){if(!safeFallback||original.signal.aborted)throw error} // Same backend, same authorization, one SDK session. Never replay writes. return attempt(original.url,fallbackTimeout); }; } window.CateriumCloudTransport=Object.freeze({create}); })();