Files
khadhroony-bobobot/kb_app/frontend/ts/demo_pipeline.ts
2026-05-01 12:01:13 +02:00

531 lines
23 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// file: kb_app/frontend/ts/demo_pipeline.ts
import * as bootstrap from "bootstrap";
import "simplebar";
import ResizeObserver from "resize-observer-polyfill";
import { invoke } from "@tauri-apps/api/core";
import { debug, takeoverConsole } from "@fltsci/tauri-plugin-tracing";
import { KbDemoPipelineInspectRequest } from './bindings/KbDemoPipelineInspectRequest.ts';
import { KbDemoPipelineInspectPayload } from './bindings/KbDemoPipelineInspectPayload.ts';
import { KbDemoPipelineInspectTokenRequest } from './bindings/KbDemoPipelineInspectTokenRequest.ts';
import { KbDemoPipelineInspectPairRequest } from './bindings/KbDemoPipelineInspectPairRequest.ts';
import { KbDemoPipelineInspectPoolRequest } from './bindings/KbDemoPipelineInspectPoolRequest.ts';
import { KbDemoPipelineBackfillTokenRequest } from './bindings/KbDemoPipelineBackfillTokenRequest.ts';
import { KbDemoPipelineBackfillTokenPayload } from './bindings/KbDemoPipelineBackfillTokenPayload.ts';
(window as Window & typeof globalThis & { bootstrap?: typeof bootstrap }).bootstrap = bootstrap;
(window as Window & typeof globalThis & { ResizeObserver?: typeof ResizeObserver }).ResizeObserver = ResizeObserver;
function appendLogLine(textarea: HTMLTextAreaElement, line: string): void {
const now = new Date();
const timestamp = now.toLocaleTimeString("fr-CH", { hour12: false });
const lines = textarea.value === "" ? [] : textarea.value.split("\n");
lines.push(`[${timestamp}] ${line}`);
const maxLines = 300;
textarea.value = lines.slice(-maxLines).join("\n");
textarea.scrollTop = textarea.scrollHeight;
}
function clearInspection(
backfillTextarea: HTMLTextAreaElement,
summaryTextarea: HTMLTextAreaElement,
transactionTextarea: HTMLTextAreaElement,
decodedEventsTextarea: HTMLTextAreaElement,
poolsTextarea: HTMLTextAreaElement,
pairsTextarea: HTMLTextAreaElement,
launchAttributionsTextarea: HTMLTextAreaElement,
poolOriginsTextarea: HTMLTextAreaElement,
walletsTextarea: HTMLTextAreaElement,
tradeEventsTextarea: HTMLTextAreaElement,
pairMetricsTextarea: HTMLTextAreaElement,
pairCandlesTextarea: HTMLTextAreaElement,
pairAnalyticSignalsTextarea: HTMLTextAreaElement,
): void {
backfillTextarea.value = "";
summaryTextarea.value = "";
transactionTextarea.value = "";
decodedEventsTextarea.value = "";
poolsTextarea.value = "";
pairsTextarea.value = "";
launchAttributionsTextarea.value = "";
poolOriginsTextarea.value = "";
walletsTextarea.value = "";
tradeEventsTextarea.value = "";
pairMetricsTextarea.value = "";
pairCandlesTextarea.value = "";
pairAnalyticSignalsTextarea.value = "";
}
function readCustomTimeframeSeconds(
input: HTMLInputElement,
logTextarea: HTMLTextAreaElement,
): bigint | null | undefined {
const customTimeframeText = input.value.trim();
if (customTimeframeText === "") {
return null;
}
const parsed = Number.parseInt(customTimeframeText, 10);
if (Number.isNaN(parsed) || parsed <= 0) {
appendLogLine(logTextarea, `[ui] invalid custom timeframe '${customTimeframeText}'`);
return undefined;
}
return BigInt(parsed);
}
function readPositiveIntegerInput(
input: HTMLInputElement,
logTextarea: HTMLTextAreaElement,
label: string,
): number | undefined {
const text = input.value.trim();
if (text === "") {
appendLogLine(logTextarea, `[ui] ${label} is required`);
return undefined;
}
const parsed = Number.parseInt(text, 10);
if (Number.isNaN(parsed) || parsed <= 0) {
appendLogLine(logTextarea, `[ui] invalid ${label} '${text}'`);
return undefined;
}
return parsed;
}
document.addEventListener("DOMContentLoaded", async () => {
void takeoverConsole();
debug("demo_pipeline window loaded");
const sidebarToggle = document.querySelector<HTMLButtonElement>('#sidebarToggle');
if (sidebarToggle) {
// restaurer létat depuis localStorage
if (localStorage.getItem('sidebar-toggle') === 'true') {
document.body.classList.add('sidenav-toggled');
}
sidebarToggle.addEventListener('click', (event) => {
event.preventDefault();
document.body.classList.toggle('sidenav-toggled');
localStorage.setItem('sidebar-toggle', document.body.classList.contains('sidenav-toggled') ? 'true' : 'false');
});
}
const tooltipTriggerList = document.querySelectorAll('[data-bs-toggle="tooltip"]');
Array.from(tooltipTriggerList).map(tooltipTriggerEl => new bootstrap.Tooltip(tooltipTriggerEl));
const toastElList = document.querySelectorAll('.toast');
Array.from(toastElList).map(toastEl => new bootstrap.Toast(toastEl));
const popoverTriggerList = document.querySelectorAll('[data-bs-toggle="popover"]');
Array.from(popoverTriggerList).map(popoverTriggerEl => new bootstrap.Popover(popoverTriggerEl));
const gobackto = location.pathname + location.search;
document.querySelectorAll<HTMLAnchorElement>('a[data-setlang]').forEach((a) => {
const href = a.getAttribute("href");
if (!href) return; // pas de href => on ignore
const url = new URL(href, location.origin);
url.searchParams.set("gobackto", gobackto);
// conserve une URL relative (path + query)
a.setAttribute("href", url.pathname + "?" + url.searchParams.toString());
});
const signatureInput = document.querySelector<HTMLInputElement>("#demoPipelineSignatureInput");
const customTimeframeInput = document.querySelector<HTMLInputElement>("#demoPipelineCustomTimeframeInput");
const inspectButton = document.querySelector<HTMLButtonElement>("#demoPipelineInspectButton");
const clearButton = document.querySelector<HTMLButtonElement>("#demoPipelineClearButton");
const clearLogButton = document.querySelector<HTMLButtonElement>("#demoPipelineClearLogButton");
const summaryTextarea = document.querySelector<HTMLTextAreaElement>("#demoPipelineSummaryTextarea");
const transactionTextarea = document.querySelector<HTMLTextAreaElement>("#demoPipelineTransactionTextarea");
const decodedEventsTextarea = document.querySelector<HTMLTextAreaElement>("#demoPipelineDecodedEventsTextarea");
const poolsTextarea = document.querySelector<HTMLTextAreaElement>("#demoPipelinePoolsTextarea");
const pairsTextarea = document.querySelector<HTMLTextAreaElement>("#demoPipelinePairsTextarea");
const launchAttributionsTextarea = document.querySelector<HTMLTextAreaElement>("#demoPipelineLaunchAttributionsTextarea");
const poolOriginsTextarea = document.querySelector<HTMLTextAreaElement>("#demoPipelinePoolOriginsTextarea");
const walletsTextarea = document.querySelector<HTMLTextAreaElement>("#demoPipelineWalletsTextarea");
const tradeEventsTextarea = document.querySelector<HTMLTextAreaElement>("#demoPipelineTradeEventsTextarea");
const pairMetricsTextarea = document.querySelector<HTMLTextAreaElement>("#demoPipelinePairMetricsTextarea");
const pairCandlesTextarea = document.querySelector<HTMLTextAreaElement>("#demoPipelinePairCandlesTextarea");
const pairAnalyticSignalsTextarea = document.querySelector<HTMLTextAreaElement>("#demoPipelinePairAnalyticSignalsTextarea");
const logTextarea = document.querySelector<HTMLTextAreaElement>("#demoPipelineLogTextarea");
const tokenMintInput = document.querySelector<HTMLInputElement>("#demoPipelineTokenMintInput");
const inspectTokenButton = document.querySelector<HTMLButtonElement>("#demoPipelineInspectTokenButton");
const pairIdInput = document.querySelector<HTMLInputElement>("#demoPipelinePairIdInput");
const inspectPairButton = document.querySelector<HTMLButtonElement>("#demoPipelineInspectPairButton");
const poolAddressInput = document.querySelector<HTMLInputElement>("#demoPipelinePoolAddressInput");
const inspectPoolButton = document.querySelector<HTMLButtonElement>("#demoPipelineInspectPoolButton");
const backfillTokenMintInput = document.querySelector<HTMLInputElement>("#demoPipelineBackfillTokenMintInput");
const backfillHttpRoleInput = document.querySelector<HTMLInputElement>("#demoPipelineBackfillHttpRoleInput");
const backfillMintLimitInput = document.querySelector<HTMLInputElement>("#demoPipelineBackfillMintLimitInput");
const backfillPoolLimitInput = document.querySelector<HTMLInputElement>("#demoPipelineBackfillPoolLimitInput");
const backfillTokenButton = document.querySelector<HTMLButtonElement>("#demoPipelineBackfillTokenButton");
const backfillTextarea = document.querySelector<HTMLTextAreaElement>("#demoPipelineBackfillTextarea");
if (
!backfillTokenMintInput ||
!backfillHttpRoleInput ||
!backfillMintLimitInput ||
!backfillPoolLimitInput ||
!backfillTokenButton ||
!backfillTextarea ||
!pairIdInput ||
!inspectPairButton ||
!poolAddressInput ||
!inspectPoolButton ||
!tokenMintInput ||
!inspectTokenButton ||
!signatureInput ||
!customTimeframeInput ||
!inspectButton ||
!clearButton ||
!clearLogButton ||
!summaryTextarea ||
!transactionTextarea ||
!decodedEventsTextarea ||
!poolsTextarea ||
!pairsTextarea ||
!launchAttributionsTextarea ||
!poolOriginsTextarea ||
!walletsTextarea ||
!tradeEventsTextarea ||
!pairMetricsTextarea ||
!pairCandlesTextarea ||
!pairAnalyticSignalsTextarea ||
!logTextarea
) {
console.error("demo_pipeline DOM is incomplete");
return;
}
clearButton.addEventListener("click", () => {
clearInspection(
backfillTextarea,
summaryTextarea,
transactionTextarea,
decodedEventsTextarea,
poolsTextarea,
pairsTextarea,
launchAttributionsTextarea,
poolOriginsTextarea,
walletsTextarea,
tradeEventsTextarea,
pairMetricsTextarea,
pairCandlesTextarea,
pairAnalyticSignalsTextarea,
);
backfillTokenMintInput.value = "";
backfillHttpRoleInput.value = "history_backfill";
backfillMintLimitInput.value = "50";
backfillPoolLimitInput.value = "50";
signatureInput.value = "";
customTimeframeInput.value = "";
tokenMintInput.value = "";
pairIdInput.value = "";
poolAddressInput.value = "";
appendLogLine(logTextarea, "[ui] inspection state cleared");
});
clearLogButton.addEventListener("click", () => {
logTextarea.value = "";
});
inspectButton.addEventListener("click", async () => {
const signature = signatureInput.value.trim();
if (signature === "") {
appendLogLine(logTextarea, "[ui] signature is required");
return;
}
let customTimeframeSeconds: bigint | null = null;
const customTimeframeText = customTimeframeInput.value.trim();
if (customTimeframeText !== "") {
const parsed = Number.parseInt(customTimeframeText, 10);
if (Number.isNaN(parsed) || parsed <= 0) {
appendLogLine(logTextarea, `[ui] invalid custom timeframe '${customTimeframeText}'`);
return;
}
customTimeframeSeconds = BigInt(parsed);
}
appendLogLine(
logTextarea,
`[ui] inspecting signature '${signature}'${customTimeframeSeconds === null ? "" : ` with custom timeframe ${customTimeframeSeconds}s`}`,
);
const request: KbDemoPipelineInspectRequest = {
signature,
customTimeframeSeconds,
};
try {
const payload = await invoke<KbDemoPipelineInspectPayload>("demo_pipeline_inspect_signature", { request });
summaryTextarea.value = payload.summaryJson;
transactionTextarea.value = payload.transactionJson;
decodedEventsTextarea.value = payload.decodedEventsJson;
poolsTextarea.value = payload.poolsJson;
pairsTextarea.value = payload.pairsJson;
launchAttributionsTextarea.value = payload.launchAttributionsJson;
poolOriginsTextarea.value = payload.poolOriginsJson;
walletsTextarea.value = payload.walletsJson;
tradeEventsTextarea.value = payload.tradeEventsJson;
pairMetricsTextarea.value = payload.pairMetricsJson;
pairCandlesTextarea.value = payload.pairCandlesJson;
pairAnalyticSignalsTextarea.value = payload.pairAnalyticSignalsJson;
appendLogLine(logTextarea, `[ui] inspection completed for '${payload.signature}'`);
} catch (error) {
appendLogLine(logTextarea, `[ui] inspect error: ${String(error)}`);
}
});
inspectTokenButton.addEventListener("click", async () => {
const tokenMint = tokenMintInput.value.trim();
if (tokenMint === "") {
appendLogLine(logTextarea, "[ui] token mint is required");
return;
}
let customTimeframeSeconds: bigint | null = null;
const customTimeframeText = customTimeframeInput.value.trim();
if (customTimeframeText !== "") {
const parsed = Number.parseInt(customTimeframeText, 10);
if (Number.isNaN(parsed) || parsed <= 0) {
appendLogLine(logTextarea, `[ui] invalid custom timeframe '${customTimeframeText}'`);
return;
}
customTimeframeSeconds = BigInt(parsed);
}
appendLogLine(
logTextarea,
`[ui] inspecting token mint '${tokenMint}'${customTimeframeSeconds === null ? "" : ` with custom timeframe ${customTimeframeSeconds}s`}`,
);
const request: KbDemoPipelineInspectTokenRequest = {
tokenMint,
customTimeframeSeconds,
};
try {
const payload = await invoke<KbDemoPipelineInspectPayload>("demo_pipeline_inspect_token_mint", { request });
summaryTextarea.value = payload.summaryJson;
transactionTextarea.value = payload.transactionJson;
decodedEventsTextarea.value = payload.decodedEventsJson;
poolsTextarea.value = payload.poolsJson;
pairsTextarea.value = payload.pairsJson;
launchAttributionsTextarea.value = payload.launchAttributionsJson;
poolOriginsTextarea.value = payload.poolOriginsJson;
walletsTextarea.value = payload.walletsJson;
tradeEventsTextarea.value = payload.tradeEventsJson;
pairMetricsTextarea.value = payload.pairMetricsJson;
pairCandlesTextarea.value = payload.pairCandlesJson;
pairAnalyticSignalsTextarea.value = payload.pairAnalyticSignalsJson;
appendLogLine(logTextarea, `[ui] token inspection completed for '${payload.signature}'`);
} catch (error) {
appendLogLine(logTextarea, `[ui] token inspect error: ${String(error)}`);
}
});
inspectPairButton.addEventListener("click", async () => {
const pairIdText = pairIdInput.value.trim();
if (pairIdText === "") {
appendLogLine(logTextarea, "[ui] pair id is required");
return;
}
const parsedPairId = Number.parseInt(pairIdText, 10);
if (Number.isNaN(parsedPairId) || parsedPairId <= 0) {
appendLogLine(logTextarea, `[ui] invalid pair id '${pairIdText}'`);
return;
}
const customTimeframeSeconds = readCustomTimeframeSeconds(customTimeframeInput, logTextarea);
if (customTimeframeSeconds === undefined) {
return;
}
appendLogLine(
logTextarea,
`[ui] inspecting pair id '${parsedPairId}'${customTimeframeSeconds === null ? "" : ` with custom timeframe ${customTimeframeSeconds}s`}`,
);
const request: KbDemoPipelineInspectPairRequest = {
pairId: BigInt(parsedPairId),
customTimeframeSeconds,
};
try {
const payload = await invoke<KbDemoPipelineInspectPayload>("demo_pipeline_inspect_pair_id", { request });
summaryTextarea.value = payload.summaryJson;
transactionTextarea.value = payload.transactionJson;
decodedEventsTextarea.value = payload.decodedEventsJson;
poolsTextarea.value = payload.poolsJson;
pairsTextarea.value = payload.pairsJson;
launchAttributionsTextarea.value = payload.launchAttributionsJson;
poolOriginsTextarea.value = payload.poolOriginsJson;
walletsTextarea.value = payload.walletsJson;
tradeEventsTextarea.value = payload.tradeEventsJson;
pairMetricsTextarea.value = payload.pairMetricsJson;
pairCandlesTextarea.value = payload.pairCandlesJson;
pairAnalyticSignalsTextarea.value = payload.pairAnalyticSignalsJson;
appendLogLine(logTextarea, `[ui] pair inspection completed for '${payload.signature}'`);
} catch (error) {
appendLogLine(logTextarea, `[ui] pair inspect error: ${String(error)}`);
}
});
inspectPoolButton.addEventListener("click", async () => {
const poolAddress = poolAddressInput.value.trim();
if (poolAddress === "") {
appendLogLine(logTextarea, "[ui] pool address is required");
return;
}
const customTimeframeSeconds = readCustomTimeframeSeconds(customTimeframeInput, logTextarea);
if (customTimeframeSeconds === undefined) {
return;
}
appendLogLine(
logTextarea,
`[ui] inspecting pool '${poolAddress}'${customTimeframeSeconds === null ? "" : ` with custom timeframe ${customTimeframeSeconds}s`}`,
);
const request: KbDemoPipelineInspectPoolRequest = {
poolAddress,
customTimeframeSeconds,
};
try {
const payload = await invoke<KbDemoPipelineInspectPayload>("demo_pipeline_inspect_pool_address", { request });
summaryTextarea.value = payload.summaryJson;
transactionTextarea.value = payload.transactionJson;
decodedEventsTextarea.value = payload.decodedEventsJson;
poolsTextarea.value = payload.poolsJson;
pairsTextarea.value = payload.pairsJson;
launchAttributionsTextarea.value = payload.launchAttributionsJson;
poolOriginsTextarea.value = payload.poolOriginsJson;
walletsTextarea.value = payload.walletsJson;
tradeEventsTextarea.value = payload.tradeEventsJson;
pairMetricsTextarea.value = payload.pairMetricsJson;
pairCandlesTextarea.value = payload.pairCandlesJson;
pairAnalyticSignalsTextarea.value = payload.pairAnalyticSignalsJson;
appendLogLine(logTextarea, `[ui] pool inspection completed for '${payload.signature}'`);
} catch (error) {
appendLogLine(logTextarea, `[ui] pool inspect error: ${String(error)}`);
}
});
backfillTokenButton.addEventListener("click", async () => {
const tokenMint = backfillTokenMintInput.value.trim();
if (tokenMint === "") {
appendLogLine(logTextarea, "[ui] backfill token mint is required");
return;
}
const mintSignatureLimit = readPositiveIntegerInput(
backfillMintLimitInput,
logTextarea,
"mintSignatureLimit",
);
if (mintSignatureLimit === undefined) {
return;
}
const poolSignatureLimit = readPositiveIntegerInput(
backfillPoolLimitInput,
logTextarea,
"poolSignatureLimit",
);
if (poolSignatureLimit === undefined) {
return;
}
const httpRoleText = backfillHttpRoleInput.value.trim();
const httpRole = httpRoleText === "" ? null : httpRoleText;
appendLogLine(
logTextarea,
`[ui] launching token backfill for '${tokenMint}' with role '${httpRole ?? "history_backfill"}' (mint=${mintSignatureLimit}, pool=${poolSignatureLimit})`,
);
const request: KbDemoPipelineBackfillTokenRequest = {
tokenMint,
httpRole,
mintSignatureLimit,
poolSignatureLimit,
};
try {
const payload = await invoke<KbDemoPipelineBackfillTokenPayload>(
"demo_pipeline_backfill_token_mint",
{ request },
);
backfillTextarea.value = payload.backfillJson;
appendLogLine(
logTextarea,
`[ui] token backfill completed for '${payload.tokenMint}' with role '${payload.httpRole}'`,
);
if (!payload.tokenPersistedAfterBackfill) {
appendLogLine(
logTextarea,
`[ui] backfill completed but token '${payload.tokenMint}' is still absent from persisted token objects; automatic token inspection skipped`,
);
return;
}
const inspectRequest: KbDemoPipelineInspectTokenRequest = {
tokenMint: payload.tokenMint,
customTimeframeSeconds: null,
};
try {
const inspectPayload = await invoke<KbDemoPipelineInspectPayload>(
"demo_pipeline_inspect_token_mint",
{ request: inspectRequest },
);
summaryTextarea.value = inspectPayload.summaryJson;
transactionTextarea.value = inspectPayload.transactionJson;
decodedEventsTextarea.value = inspectPayload.decodedEventsJson;
poolsTextarea.value = inspectPayload.poolsJson;
pairsTextarea.value = inspectPayload.pairsJson;
launchAttributionsTextarea.value = inspectPayload.launchAttributionsJson;
poolOriginsTextarea.value = inspectPayload.poolOriginsJson;
walletsTextarea.value = inspectPayload.walletsJson;
tradeEventsTextarea.value = inspectPayload.tradeEventsJson;
pairMetricsTextarea.value = inspectPayload.pairMetricsJson;
pairCandlesTextarea.value = inspectPayload.pairCandlesJson;
pairAnalyticSignalsTextarea.value = inspectPayload.pairAnalyticSignalsJson;
appendLogLine(
logTextarea,
`[ui] token inspection refreshed after backfill for '${payload.tokenMint}'`,
);
} catch (error) {
appendLogLine(
logTextarea,
`[ui] backfill completed but automatic token inspection failed for '${payload.tokenMint}': ${String(error)}`,
);
}
} catch (error) {
appendLogLine(logTextarea, `[ui] token backfill error: ${String(error)}`);
}
});
});