CHAT_OUTPUT_BEGIN COMMAND_ID=GRAM1-SITE-CHARTS-NO-DATA-V25-READ-ONLY-EXACT-DIAG-20260801T092900Z STATUS=OK RC=0 HOST=pve01 MODE=verify COMPONENT=gram1-site-charts-no-data-v25-read-only-exact-diag REFERENCE_REGISTER_CHECK=OK REFERENCE_SHA256=5763f2f8edc75fcf6f3951f8c95896d1cc112ceccb6cf5b64a383f540a4deb8e ERROR_REGISTER_CHECK=OK ERROR_REGISTER_SHA256=24934a2c7fa5c26f6e828583c4aefac7f143b40c0171736ed7571e617d55ab83 COMMAND_SHA256=63f257115dd000cfe86eb63dadd592cea3306949f5184917bbb497f3b1211198 DUPLICATE_FAILED_COMMAND_BLOCKED=false EXECUTION_STARTED=true CHANGE_DECLARED=false RESULT_CONTRACT_VALID=true RESULT_CONTRACT_STATUS=NOT_APPLICABLE RESULT_CONTRACT_ERROR=NONE COMMAND_RC=0 CHANGES_MADE=false ROLLBACK_STARTED=false ROLLBACK_RESTORED=null MUTATION_OUTCOME=NO_MUTATION SANITIZED=yes SECRETS_INCLUDED=no PRIVATE_ADDRESSES_INCLUDED=no RAW_EVIDENCE_SHA256=d3af4505d9a03ba1654bc4d93fc339225bb570a30d2ab62cd76f51496935ba75 SANITIZED_OUTPUT_SHA256=d3af4505d9a03ba1654bc4d93fc339225bb570a30d2ab62cd76f51496935ba75 OUTPUT_BEGIN HOMELAB_RESULT_CONTRACT={"changes_made":false,"command_id":"GRAM1-SITE-CHARTS-NO-DATA-V25-READ-ONLY-EXACT-DIAG-20260801T092900Z","mutation_outcome":"NO_MUTATION","rollback_restored":null,"rollback_started":false,"status":"OK","version":1} {"changes_made":false,"command_id":"GRAM1-SITE-CHARTS-NO-DATA-V25-READ-ONLY-EXACT-DIAG-20260801T092900Z","control_plane_error":null,"gitea_changed":false,"mutation_outcome":"NO_MUTATION","previous_capsule_sha256":"a7143b656e161f0f0312e43cc0c6f59840953dfa414537cc2881dd37b2739439","previous_command_id":"GRAM1-SITE-POL-ACCORDION-V24-ATOMIC-UI-FIX-20260801T092200Z","previous_output_sha256":"6c1c2b55816a60b410b09865a069ba9a7feec2a1d6f90d90c5947d2c10c8ab8f","previous_runner_json_sha256":"fd9459ab8e69940ad23be7e4aa3d1b8ffc68a08b83425967a3244891389e9de2","previous_runner_text_sha256":"279ecb54d524871dce71eb4a34e6d46fd95a70a3ae712035914cc40b752bbf96","production_site_changed":false,"rc":0,"remote_result":{"changes_made":false,"checks":{"app_routes":[{"decorator":"app.get('/login', response_class=HTMLResponse)","function":"login_page","line":53,"path":"/login"},{"decorator":"app.post('/login')","function":"login","line":59,"path":"/login"},{"decorator":"app.post('/logout')","function":"logout","line":74,"path":"/logout"},{"decorator":"app.get('/', response_class=HTMLResponse)","function":"home","line":79,"path":"/"},{"decorator":"app.get('/health')","function":"health","line":85,"path":"/health"},{"decorator":"app.get('/coin-icon/{coin_id}')","function":"coin_icon","line":93,"path":"/coin-icon/{coin_id}"},{"decorator":"app.get('/vendor/lightweight-charts.js')","function":"lightweight_charts_js","line":142,"path":"/vendor/lightweight-charts.js"},{"decorator":"app.get('/api/klines/{symbol}')","function":"klines","line":308,"path":"/api/klines/{symbol}"},{"decorator":"app.get('/api/chart-health')","function":"chart_health","line":313,"path":"/api/chart-health"},{"decorator":"app.get('/api/state')","function":"state","line":347,"path":"/api/state"},{"decorator":"app.post('/api/holding')","function":"save_holding","line":364,"path":"/api/holding"},{"decorator":"app.post('/api/alert')","function":"add_alert","line":377,"path":"/api/alert"},{"decorator":"app.delete('/api/alert/{alert_id}')","function":"delete_alert","line":391,"path":"/api/alert/{alert_id}"}],"compose_sha256":"6d344e46b3de94ad86131a914df2ff3ff25e9d82f7ce0557cbffa468b8cdc1b8","data":{"files":[{"bytes":20963,"name":"klines-cache.json","sha256":"c37fd69ccd9f027fa5c97a4e405cd731feb7a7519c05ef4c2d88ac07182fd201","symbols":{"AVAX":{"count":2,"present":true},"HBAR":{"count":2,"present":true},"LINK":{"count":2,"present":true},"POL":{"count":2,"present":true}},"top_keys":["entries","saved_at","version"]},{"bytes":13860,"name":"market.json","sha256":"d964ce60028612f44c9da3a61cbd2b7831f4a70784be683da3580d010659de3f","symbols":{"AVAX":{"count":1,"present":true},"HBAR":{"count":1,"present":true},"LINK":{"count":1,"present":true},"POL":{"count":2,"present":true}},"top_keys":["coins","currency","updated_at","usd_rub"]},{"bytes":96,"name":"worker-status.json","sha256":"ca07f70b4037b5f9890a8a08709baa30680263bf810fecc08682b99df72b4b82","symbols":{"AVAX":{"count":0,"present":false},"HBAR":{"count":0,"present":false},"LINK":{"count":0,"present":false},"POL":{"count":0,"present":false}},"top_keys":["alerts_triggered","coin_count","history_rows","status","updated_at"]}],"now":1785576765},"diagnostic_flags":["NO_TRADINGVIEW_WIDGET_INITIALIZER_FOUND","NO_DATA_FALLBACK_EXISTS_IN_FRONTEND","CHART_ERROR_PLACEHOLDER_PRESENT","HOMEPAGE_NOT_200"],"exact_file_hashes":{"app.py":"ec226952cdb7fb58edbfc0173af47f4d901f3206e15169df12294983731fbc20","templates/index.html":"595fec2f7a1dc7ffac4a2ce7f6703c25608a775bebee492b2143cf9792789696","worker.py":"4a7b16ece826fe2d938f392db6b0b5ca028dcb6ff02fdff4ab431f114edf0e5c"},"external_script_probe":[{"skipped":"relative","url":"/vendor/lightweight-charts.js"}],"next_decision":"FIX_ONLY_PROVEN_NO_DATA_CAUSE_WITH_ONE_ATOMIC_TRANSACTION","runtime":{"ports":[8000,5000,8080,3000,80,35961],"routes":[{"bytes":0,"contains":{"POL":false,"TradingView":false,"Нет данных":false},"content_type":null,"external_scripts":[],"focus":[],"headers":{"cache-control":null,"content-security-policy":null,"x-frame-options":null},"inline_script_count":0,"path":"/","port":8000,"sha256":"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855","status":303},{"bytes":66,"contains":{"POL":false,"TradingView":false,"Нет данных":false},"content_type":"application/json","headers":{"cache-control":null,"content-security-policy":null,"x-frame-options":null},"json":{"market_age_seconds":258,"status":"OK","type":"crypto-portfolio"},"path":"/health","port":8000,"sha256":"1c5a784dabda5571bc1411d064b364ddff7085a2fa503ea4ca9d3c0eed3e5e56","status":200},{"bytes":450,"contains":{"POL":true,"TradingView":false,"Нет данных":false},"content_type":"application/json","headers":{"cache-control":null,"content-security-policy":null,"x-frame-options":null},"json":{"bad":0,"disk_cache_present":true,"library_ok":true,"status":"OK","symbols":{"AVAX":{"cache_age_seconds":127,"candles":72,"source":"binance","stale":false,"status":"OK"},"HBAR":{"cache_age_seconds":127,"candles":84,"source":"binance","stale":false,"status":"OK"},"LINK":{"cache_age_seconds":127,"candles":92,"source":"binance","stale":false,"status":"OK"},"POL":{"cache_age_seconds":127,"candles":24,"source":"binance","stale":false,"status":"OK"}}},"path":"/api/chart-health","port":8000,"sha256":"e345436fd16349538387e51a62b494a6a727e0f04b65249837398100fa9d89d2","status":200},{"bytes":1088,"contains":{"POL":false,"TradingView":false,"Нет данных":false},"content_type":"text/html; charset=utf-8","focus":[],"headers":{"cache-control":null,"content-security-policy":null,"x-frame-options":null},"path":"/login","port":8000,"sha256":"66b06909949879d84757d0f96be74eebf1db40f35de22b625ea67e85e1bbdae2","status":200},{"bytes":31,"contains":{"POL":false,"TradingView":false,"Нет данных":false},"content_type":"application/json","headers":{"cache-control":null,"content-security-policy":null,"x-frame-options":null},"json":{"detail":"Method Not Allowed"},"path":"/logout","port":8000,"sha256":"83c09ba9a8daedb136f90b17a294caa90ad471a016e430df6e229acb5a81e100","status":405},{"bytes":196203,"contains":{"POL":false,"TradingView":true,"Нет данных":false},"content_type":"application/javascript","focus":["/*! * @license * TradingView Lightweight Charts™ v5.2.0 * Copyright (c) 2026 TradingView, Inc. * Licensed under Apache License 2.0 https://www.apache.org/licenses/LICENSE-2.0 */ !function(){\"use strict\";const t={title:\"\",visible:!0,hitTestTolerance:3,lastValueVisible:!0,priceLineVisible:!0,priceLineSource:0,priceLineWidth:1,priceLineColor:\"\",priceLineStyle:2,baseLineVisible:!0,baseLineWidth:1,baseLineColor:\"#B2B5BE\",baseLineStyle:0,priceFormat:{type:\"price\",precision:2,minMove:.01}};var i,n;function s(t,i){const n=function(t,i){switch(t){case 0:default:return[];case 1:return[i,i];case 2:return[2*i,2*i];case 3:return[6*i,6*i];case 4:return[i,4*i]}}(i,t.lineWidth);return t.setLineDash(n),n}function e(t,i,n,s){t.beginPath();const e=t.lineWidth%2?.5:0;t.moveTo(n,i+e),t.lineTo(s,i+e),t.stroke()}function r(t,i){if(!t)throw new Error(\"Assertion failed\"+(i?\": \"+i:\"\"))}function h(t){if(void 0===t)throw new Error(\"Value i","/*! * @license * TradingView Lightweight Charts™ v5.2.0 * Copyright (c) 2026 TradingView, Inc. * Licensed under Apache License 2.0 https://www.apache.org/licenses/LICENSE-2.0 */ !function(){\"use strict\";const t={title:\"\",visible:!0,hitTestTolerance:3,lastValueVisible:!0,priceLineVisible:!0,priceLineSource:0,priceLineWidth:1,priceLineColor:\"\",priceLineStyle:2,baseLineVisible:!0,baseLineWidth:1,baseLineColor:\"#B2B5BE\",baseLineStyle:0,priceFormat:{type:\"price\",precision:2,minMove:.01}};var i,n;function s(t,i){const n=function(t,i){switch(t){case 0:default:return[];case 1:return[i,i];case 2:return[2*i,2*i];case 3:return[6*i,6*i];case 4:return[i,4*i]}}(i,t.lineWidth);return t.setLineDash(n),n}function e(t,i,n,s){t.beginPath();const e=t.lineWidth%2?.5:0;t.moveTo(n,i+e),t.lineTo(s,i+e),t.stroke()}function r(t,i){if(!t)throw new Error(\"Assertion failed\"+(i?\": \"+i:\"\"))}function h(t){if(void 0===t)throw new Error(\"Value is undefined\");return t}function a(t){if(null===t)throw new Er","Logo}Jv(){const t=new URL(location.href);return t.hostname?\"&utm_source=\"+t.hostname+t.pathname:\"\"}Yv(){this.Zv()&&(this.Kv(),this.vn=this.Gv(),this.vn&&(this.$v=this.Xv(),this.Uv=document.createElement(\"style\"),this.Uv.innerText=\"a#tv-attr-logo{--fill:#131722;--stroke:#fff;position:absolute;left:10px;bottom:10px;height:19px;width:35px;margin:0;padding:0;border:0;z-index:3;}a#tv-attr-logo[data-dark]{--fill:#D1D4DC;--stroke:#131722;}\",this.Hv=document.createElement(\"a\"),this.Hv.href=`https://www.tradingview.com/?utm_medium=lwc-link&utm_campaign=lwc-chart${this.Jv()}`,this.Hv.title=\"Charting by TradingView\",this.Hv.id=\"tv-attr-logo\",this.Hv.target=\"_blank\",this.Hv.innerHTML='',this.Hv.toggleAttribute(\"data-dark\",\"dark\"===this.$v),this.jv.appendChild(this.Uv),this.jv.appendChild(this.Hv)))}}function Vn(t,i){const n=a(t.ownerDocument).","v(){this.Zv()&&(this.Kv(),this.vn=this.Gv(),this.vn&&(this.$v=this.Xv(),this.Uv=document.createElement(\"style\"),this.Uv.innerText=\"a#tv-attr-logo{--fill:#131722;--stroke:#fff;position:absolute;left:10px;bottom:10px;height:19px;width:35px;margin:0;padding:0;border:0;z-index:3;}a#tv-attr-logo[data-dark]{--fill:#D1D4DC;--stroke:#131722;}\",this.Hv=document.createElement(\"a\"),this.Hv.href=`https://www.tradingview.com/?utm_medium=lwc-link&utm_campaign=lwc-chart${this.Jv()}`,this.Hv.title=\"Charting by TradingView\",this.Hv.id=\"tv-attr-logo\",this.Hv.target=\"_blank\",this.Hv.innerHTML='',this.Hv.toggleAttribute(\"data-dark\",\"dark\"===this.$v),this.jv.appendChild(this.Uv),this.jv.appendChild(this.Hv)))}}function Vn(t,i){const n=a(t.ownerDocument).createElement(\"canvas\");t.appendChild(n);const s=new cn(n,(e={options:{allowResizeObserver:!0},trans"],"headers":{"cache-control":"public, max-age=31536000, immutable","content-security-policy":null,"x-frame-options":null},"path":"/vendor/lightweight-charts.js","port":8000,"sha256":"c0992580867c4912cc9385b3c2728315bcc1a76c7f1087dca908430fccdf31d7","status":200},{"bytes":27,"contains":{"POL":false,"TradingView":false,"Нет данных":false},"content_type":"application/json","headers":{"cache-control":null,"content-security-policy":null,"x-frame-options":null},"json":{"detail":"login required"},"path":"/api/state","port":8000,"sha256":"913db652b5cf6ba54020fa7426c642b69f1c868742feddc69fd4077076d942d9","status":401},{"bytes":31,"contains":{"POL":false,"TradingView":false,"Нет данных":false},"content_type":"application/json","headers":{"cache-control":null,"content-security-policy":null,"x-frame-options":null},"json":{"detail":"Method Not Allowed"},"path":"/api/holding","port":8000,"sha256":"83c09ba9a8daedb136f90b17a294caa90ad471a016e430df6e229acb5a81e100","status":405},{"bytes":31,"contains":{"POL":false,"TradingView":false,"Нет данных":false},"content_type":"application/json","headers":{"cache-control":null,"content-security-policy":null,"x-frame-options":null},"json":{"detail":"Method Not Allowed"},"path":"/api/alert","port":8000,"sha256":"83c09ba9a8daedb136f90b17a294caa90ad471a016e430df6e229acb5a81e100","status":405},{"bytes":0,"contains":{"POL":false,"TradingView":false,"Нет данных":false},"content_type":null,"focus":[],"headers":{"cache-control":null,"content-security-policy":null,"x-frame-options":null},"path":"/api/alert/","port":8000,"sha256":"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855","status":307},{"bytes":22,"contains":{"POL":false,"TradingView":false,"Нет данных":false},"content_type":"application/json","headers":{"cache-control":null,"content-security-policy":null,"x-frame-options":null},"json":{"detail":"Not Found"},"path":"/api/klines/","port":8000,"sha256":"37ec4665a8102d115ffd1ac20dae94c98b4dac64b0c1a68228aa2a531caeb35d","status":404}]},"services":{"rc":0,"stderr":"","stdout":"{\"Command\":\"\\\"uvicorn app:app --h…\\\"\",\"CreatedAt\":\"2026-08-01 12:23:15 +0300 MSK\",\"ExitCode\":0,\"Health\":\"\",\"ID\":\"fe312e150112\",\"Image\":\"crypto-portfolio-web\",\"Labels\":\"com.docker.compose.service=web,com.docker.compose.,com.docker.compose.container-number=1,com.docker.compose.depends_on=,com.docker.compose.project.config_files=/opt/stacks/crypto-portfolio/compose.yaml,com.docker.compose.,com.docker.compose.version=2.26.1,com.docker.compose.image=sha256:2f4d3926f130f414fbf92a27b6fac6eb0d97bb5b726efc5bc52360ba76b6e103,com.docker.compose.oneoff=False,com.docker.compose.project=crypto-portfolio,com.docker.compose.project.working_dir=/opt/stacks/crypto-portfolio\",\"LocalVolumes\":\"0\",\"Mounts\":\"/opt/stacks/cr…,/opt/stacks/cr…,/opt/stacks/cr…,/opt/stacks/cr…\",\"Name\":\"crypto-portfolio\",\"Names\":\"crypto-portfolio\",\"Networks\":\"crypto-portfolio_default\",\"Ports\":\":8030-\\u003e8000/tcp\",\"Project\":\"crypto-portfolio\",\"Publishers\":[{\"URL\":\"\",\"TargetPort\":8000,\"PublishedPort\":8030,\"Protocol\":\"tcp\"}],\"RunningFor\":\"9 minutes ago\",\"Service\":\"web\",\"Size\":\"0B\",\"State\":\"running\",\"Status\":\"Up 9 minutes\"}\n{\"Command\":\"\\\"python /app/worker.…\\\"\",\"CreatedAt\":\"2026-08-01 12:23:15 +0300 MSK\",\"ExitCode\":0,\"Health\":\"\",\"ID\":\"e63250c93d2b\",\"Image\":\"crypto-portfolio-worker\",\"Labels\":\"com.docker.compose.container-number=1,com.docker.compose.oneoff=False,com.docker.compose.project=crypto-portfolio,com.docker.compose.project.working_dir=/opt/stacks/crypto-portfolio,com.docker.compose.,com.docker.compose.depends_on=,com.docker.compose.image=sha256:41f34e3eb9647aba391e96336caacbddbe0db37a3a7fce8ba09b66b104a91eb4,com.docker.compose.project.config_files=/opt/stacks/crypto-portfolio/compose.yaml,com.docker.compose.,com.docker.compose.service=worker,com.docker.compose.version=2.26.1\",\"LocalVolumes\":\"0\",\"Mounts\":\"/opt/stacks/cr…,/opt/stacks/cr…\",\"Name\":\"crypto-portfolio-worker\",\"Names\":\"crypto-portfolio-worker\",\"Networks\":\"crypto-portfolio_default\",\"Ports\":\"\",\"Project\":\"crypto-portfolio\",\"Publishers\":null,\"RunningFor\":\"9 minutes ago\",\"Service\":\"worker\",\"Size\":\"0B\",\"State\":\"running\",\"Status\":\"Up 9 minutes\"}\n"},"source":{"bytes":30286,"contexts":[{"offset":7619,"pattern":"fetch\\s*\\(","text":"UB\"?\"RUB\":\"USD\";const fx=()=>Number(state&&state.market&&state.market.usd_rub||0);const cv=n=>Number(n||0)*(currency===\"RUB\"?fx():1);const money=(n,d=2)=>new Intl.NumberFormat(currency===\"RUB\"?\"ru-RU\":\"en-US\",{style:\"currency\",currency:currency,minimumFractionDigits:d,maximumFractionDigits:d}).format(cv(n));const compactMoney=n=>(currency===\"RUB\"?\"₽\":\"$\")+new Intl.NumberFormat(currency===\"RUB\"?\"ru-RU\":\"en-US\",{notation:\"compact\",maximumFractionDigits:2}).format(cv(n));const inputPrice=n=>Number((Number(n||0)*(currency===\"RUB\"?fx():1)).toFixed(currency===\"RUB\"?2:8));const coin=()=>state.market.coins[selected];async function load(){let r=await fetch(\"/api/state\");if(r.status===401){location=\"/login\";return}state=await r.json();render()}function render(){let m=state.market.coins||{};let ids=Object.keys(state.coins);/* ALERT_COIN_SELECTOR_EARLY_V1 */aCoin.innerHTML=ids.map(id=>\"\").join(\"\");if(currency===\"RUB\"&&!(fx()>0)){currency=\"USD\"}document.querySelectorAll(\".currency-btn\").forEach(x=>x.classList.toggle(\"active\",x.dataset.currency===currency));avgHeader.textContent=\"Средняя покупка (\"+currency+\")\";coins.innerHTML=ids.map(id=>{let c=m[id]||{};let ch=Number(c.change_24h||0);return \"
=0?\"good\":\"bad\";pnlp.textContent=(inv?p/inv*100:0).toFixed(2)+\"%\";day.textContent=(daily>=0?\"+\":\"\")+money(daily,2)+\" за 24ч\";updated.textContent=state.market.updated_at?new Date(state.market.updated_at*1000).toLocaleTimeString(\"ru-RU\"):\"нет данных\";marketStatus.textContent=Object.keys(m).length===2?\"Рынок обновлён\":\"Нет данных\";marketStatus.className=\"status \"+(Object.keys(m).length===2?\"good\":\"bad\");bindInputs();draw();renderMoves();renderAlerts();aCoin.innerHTML=ids.map(id=>\"\").join(\"\")}function bindInputs(){document.querySelectorAll(\".qty,.avg\").forEach(x=>x.onchange=async()=>{let id=x.dataset.id;let q=document.querySelector(\".qty[data-id=\\\"\"+id+\"\\\"]\").value;let a=document.querySelector(\".avg[data-id=\\\"\"+id+\"\\\"]\").value;let avg=currency===\"RUB\"?Number(a)/fx():Number(a);await fetch(\"/api/holding\",{method:\"POST\",headers:{\"Content-T"},{"offset":12971,"pattern":"fetch\\s*\\(","text":"k={price_above:\"цена ≥\",price_below:\"цена ≤\",cap_above:\"капитализация ≥\",cap_below:\"капитализация ≤\",pump:\"памп ≥ +\",dump:\"падение ≥ −\"}[a.kind];return c+\": \"+k+\" \"+a.threshold+(a.kind===\"pump\"||a.kind===\"dump\"?\"% за \"+Math.round(a.window_seconds/60)+\" мин\":\" USD\")}function renderAlerts(){alertList.innerHTML=state.alerts.length?state.alerts.map(a=>\"
\"+label(a)+\"
\"+a.email+\"
\").join(\"\"):\"Оповещений пока нет\";document.querySelectorAll(\".del\").forEach(x=>x.onclick=async()=>{await fetch(\"/api/alert/\"+x.dataset.id,{method:\"DELETE\"});load()})}aKind.onchange=()=>aWindow.classList.toggle(\"hidden\",!([\"pump\",\"dump\"].includes(aKind.value)));addAlert.onclick=async()=>{let dynamic=[\"pump\",\"dump\"].includes(aKind.value);let r=await fetch(\"/api/alert\",{method:\"POST\",headers:{\"Content-Type\":\"application/json\"},body:JSON.stringify({coin_id:aCoin.value,kind:aKind.value,threshold:Number(aThreshold.value),window_seconds:dynamic?Number(aWindow.value):0,email:aEmail.value})});if(!r.ok){alert(\"Проверьте параметры\")};aThreshold.value=\"\";load()};document.querySelectorAll(\".currency-btn\").forEach(x=>x.onclick=()=>{currency=x.dataset.currency;local"},{"offset":16886,"pattern":"fetch\\s*\\(","text":"lue||\"\").trim() }; statusEl.className=\"muted full\"; statusEl.textContent=\"\"; if(!payload.coin_id){statusEl.className=\"bad full\";statusEl.textContent=\"Не выбрана монета\";return;} if(!Number.isFinite(payload.threshold)||payload.threshold<=0){statusEl.className=\"bad full\";statusEl.textContent=\"Укажи положительный порог\";return;} if(!payload.email||!payload.email.includes(\"@\")){statusEl.className=\"bad full\";statusEl.textContent=\"Укажи корректный email\";return;} button.disabled=true; const oldText=button.textContent; button.textContent=\"Создание…\"; try{ const beforeResponse=await fetch(\"/api/state\",{credentials:\"same-origin\",headers:{\"Accept\":\"application/json\"}}); if(beforeResponse.status===401){location=\"/login\";return;} if(!beforeResponse.ok){throw new Error(\"предварительная проверка HTTP \"+beforeResponse.status);} const before=await beforeResponse.json(); const beforeIds=new Set((before.alerts||[]).map(a=>Number(a.id))); const response=await fetch(\"/api/alert\",{ method:\"POST\", credentials:\"same-origin\", headers:{\"Content-Type\":\"application/json\",\"Accept\":\"application/json\"}, body:JSON.stringify(payload) }); const raw=await re"},{"offset":21685,"pattern":"fetch\\s*\\(","text":"data,alert))); left.append(make(\"div\",\"muted\",alert.email||\"\")); const holding=(data.holdings&&data.holdings[alert.coin_id])||{}; const quantity=Number(holding.quantity||0); const isPrice=[\"price_above\",\"price_below\"].includes(alert.kind); const sale=make(\"div\",\"sale\",isPrice?alertMoney(data,quantity*Number(alert.threshold||0)):\"—\"); const button=make(\"button\",\"btn ghost del\",\"Удалить\"); button.type=\"button\"; button.dataset.alertDeleteV4=String(alert.id); button.onclick=async event=>{ event.preventDefault(); button.disabled=true; try{ const response=await fetch(\"/api/alert/\"+encodeURIComponent(alert.id),{method:\"DELETE\",credentials:\"same-origin\",cache:\"no-store\"}); if(response.status===401){location=\"/login\";return;} if(!response.ok)throw new Error(\"HTTP \"+response.status); await refresh(); }catch(error){ button.disabled=false; button.textContent=\"Ошибка удаления\"; } }; row.append(left,sale,button); box.append(row); }); }; const refresh=async()=>{ if(loading)return; loading=true; const box=document.getElementById(\"alertList\"); try{ const response=await fetch(\"/api/state\",{credentials:\"sa"},{"offset":23740,"pattern":"TradingView","text":"}); observer.observe(box,{childList:true,subtree:true}); } const add=document.getElementById(\"addAlert\"); if(add){ add.addEventListener(\"click\",()=>{ setTimeout(refresh,400); setTimeout(refresh,1200); }); } refresh(); setInterval(refresh,15000); }; if(document.readyState===\"loading\")document.addEventListener(\"DOMContentLoaded\",install,{once:true});else install(); const redrawForCurrency=()=>{if(lastState)draw(lastState);}; document.querySelectorAll(\".currency-btn\").forEach(button=>button.addEventListener(\"click\",()=>setTimeout(redrawForCurrency,0))); })();