Finsam Tech

Sign in to console

OR
Don't have an account?
Sign out

Analytics

How your projects are performing on the switch network.

Total Requests

Success Rate

Last 24h

Errors

Projects & Accounts

0 project(s)  ·  0 account(s) created through your API keys

Requests by Endpoint

No activity yet.
\n` ) : htmlContent + `\n\n`; const manifest = { name: safeName, short_name: safeName.slice(0, 12), start_url: "/", display: "standalone", background_color: "#ffffff", theme_color: themeColor, icons: [ { src: "/icon.svg", sizes: "any", type: "image/svg+xml", purpose: "any maskable" } ] }; const iconSvg = `${initial}`; const swScript = `const CACHE = "fst-pwa-v1"; const ASSETS = ["/", "/manifest.json", "/icon.svg"]; self.addEventListener("install", (e) => { e.waitUntil(caches.open(CACHE).then((c) => c.addAll(ASSETS))); }); self.addEventListener("fetch", (e) => { e.respondWith( caches.match(e.request).then((cached) => cached || fetch(e.request).catch(() => caches.match("/"))) ); });`; return `const HTML = ${JSON.stringify(injected)}; const MANIFEST = ${JSON.stringify(JSON.stringify(manifest))}; const ICON_SVG = ${JSON.stringify(iconSvg)}; const SW_SCRIPT = ${JSON.stringify(swScript)}; export default { async fetch(request) { const url = new URL(request.url); if (url.pathname === "/manifest.json") { return new Response(MANIFEST, { headers: { "content-type": "application/manifest+json" } }); } if (url.pathname === "/sw.js") { return new Response(SW_SCRIPT, { headers: { "content-type": "application/javascript" } }); } if (url.pathname === "/icon.svg") { return new Response(ICON_SVG, { headers: { "content-type": "image/svg+xml" } }); } return new Response(HTML, { headers: { "content-type": "text/html; charset=utf-8" } }); } };`; } async function deployWorkerNow() { const name = document.getElementById("deploy-name").value.trim(); const projectId = document.getElementById("deploy-project").value || null; const btn = document.getElementById("deploy-btn"); const terminal = document.getElementById("deploy-terminal"); let code; if (deployMode === "pwa") { const appName = document.getElementById("pwa-app-name").value.trim(); const themeColor = document.getElementById("pwa-theme-color").value; const htmlContent = document.getElementById("pwa-html-content").value; if (!appName) { terminal.innerHTML = `Error: enter an app name.`; return; } if (!htmlContent.trim()) { terminal.innerHTML = `Error: app HTML can't be empty.`; return; } code = buildPwaWorkerCode(appName, themeColor, htmlContent); } else if (deployMode === "file") { const fileContent = document.getElementById("deploy-file-content").value; const mimeType = document.getElementById("deploy-file-type").value; if (!fileContent.trim()) { terminal.innerHTML = `Error: file content can't be empty.`; return; } code = `const CONTENT = ${JSON.stringify(fileContent)};\nconst MIME = ${JSON.stringify(mimeType)};\nexport default {\n async fetch() {\n return new Response(CONTENT, { headers: { "content-type": MIME + "; charset=utf-8" } });\n }\n};`; } else { code = document.getElementById("deploy-code").value; if (!code.trim()) { terminal.innerHTML = `Error: worker.js can't be empty.`; return; } } if (!name) { terminal.innerHTML = `Error: enter a name first.`; return; } btn.disabled = true; terminal.innerHTML = `deploying "${name}"...`; await new Promise(r => setTimeout(r, 200)); appendTerminal("$ uploading script to Cloudflare..."); try { const res = await authedFetch("/deployWorker", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ name, code, projectId }), }); const data = await res.json(); if (!res.ok) { appendTerminal(`✗ deploy failed: ${data.error}`); return; } appendTerminal(`✓ script uploaded (${data.scriptName})`); await new Promise(r => setTimeout(r, 150)); appendTerminal(`✓ workers.dev route enabled`); await new Promise(r => setTimeout(r, 150)); appendTerminal(`✓ live at: ${data.url}`); if (data.updatedExisting) appendTerminal("(existing worker updated)"); loadDeployedWorkers(); } catch (e) { appendTerminal("✗ network error during deploy"); } finally { btn.disabled = false; } } async function populateDeployProjectDropdown() { const select = document.getElementById("deploy-project"); try { const res = await authedFetch("/listProjects"); const data = await res.json(); const projects = data.projects || []; select.innerHTML = `` + projects.map(p => ``).join(""); } catch (e) {} } function appendApkTerminal(text) { const el = document.getElementById("apk-terminal"); const line = document.createElement("span"); line.className = "terminal-line"; line.textContent = text; el.appendChild(document.createElement("br")); el.appendChild(line); el.scrollTop = el.scrollHeight; } async function startApkBuild() { const appName = document.getElementById("apk-app-name").value.trim(); const packageName = document.getElementById("apk-package-name").value.trim(); const targetUrl = document.getElementById("apk-target-url").value.trim(); const themeColorHex = document.getElementById("apk-theme-color").value; const btn = document.getElementById("apk-build-btn"); const terminal = document.getElementById("apk-terminal"); if (!appName || !packageName || !targetUrl) { terminal.innerHTML = `Error: fill in app name, package name, and target URL.`; return; } btn.disabled = true; terminal.innerHTML = `Starting build for "${appName}"...`; try { const res = await authedFetch("/buildApk", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ appName, packageName, targetUrl, themeColorHex }), }); const data = await res.json(); if (!res.ok) { appendApkTerminal(`✗ ${data.error}`); btn.disabled = false; return; } appendApkTerminal(`✓ build queued on GitHub Actions (id: ${data.buildId})`); appendApkTerminal(`$ compiling with Android SDK + Gradle — this takes a few minutes...`); loadApkBuilds(); pollApkBuild(data.buildId, btn, terminal); } catch (e) { appendApkTerminal("✗ network error starting build"); btn.disabled = false; } } async function pollApkBuild(buildId, btn, terminal) { const maxAttempts = 40; // ~13 minutes at 20s intervals let attempts = 0; const check = async () => { attempts++; try { const res = await authedFetch("/getBuildStatus", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ buildId }), }); const data = await res.json(); if (data.status === "completed") { appendApkTerminal(`✓ build complete!`); appendApkTerminal(`✓ download: ${data.downloadUrl}`); btn.disabled = false; loadApkBuilds(); return; } if (attempts >= maxAttempts) { appendApkTerminal(`… still building after a while — check "Your APK Builds" below periodically, it'll update once ready.`); btn.disabled = false; return; } setTimeout(check, 20000); } catch (e) { btn.disabled = false; } }; setTimeout(check, 20000); } async function loadApkBuilds() { const el = document.getElementById("apk-builds-list"); el.innerHTML = `
Loading…
`; try { const res = await authedFetch("/listApkBuilds"); const data = await res.json(); if (!data.builds || data.builds.length === 0) { el.innerHTML = `
No builds yet.
`; return; } el.innerHTML = data.builds.map((b, i) => `
${b.appName}
${b.packageName}
${b.status}
${b.status === 'completed' && b.downloadUrl ? `Download APK` : ''}
`).join(""); } catch (e) { el.innerHTML = `
Could not load builds.
`; } } async function loadDeployedWorkers() { const el = document.getElementById("deployed-list"); el.innerHTML = `
Loading…
`; populateDeployProjectDropdown(); try { const [workersRes, projectsRes] = await Promise.all([ authedFetch("/listWorkers"), authedFetch("/listProjects"), ]); const data = await workersRes.json(); const projectsData = await projectsRes.json(); const projectMap = {}; (projectsData.projects || []).forEach(p => { projectMap[p.id] = p.name; }); if (!data.workers || data.workers.length === 0) { el.innerHTML = `
No workers or files deployed yet.
`; return; } el.innerHTML = data.workers.map((w, i) => `
${w.name}
${w.projectId && projectMap[w.projectId] ? `${projectMap[w.projectId]}` : ''} ${w.url}
`).join(""); } catch (e) { el.innerHTML = `
Could not load deployments.
`; } } async function deleteWorkerNow(id) { if (!confirm("Delete this deployed Worker? This removes it from Cloudflare permanently.")) return; try { await authedFetch("/deleteWorker", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ id }), }); loadDeployedWorkers(); } catch (e) {} } async function apiKeyFetch(path, body) { const apiKey = localStorage.getItem("finsam_apikey"); const res = await fetch(`${API_BASE}${path}`, { method: "POST", headers: { "Content-Type": "application/json", "x-api-key": apiKey }, body: JSON.stringify(body), }); const data = await res.json(); return { status: res.status, data }; } const TEST_ACCT_A = "1111000001"; const TEST_ACCT_B = "1111000002"; async function testCreateAccounts() { const out = document.getElementById("test-create-out"); out.textContent = "Running…"; try { const a = await apiKeyFetch("/api/createAccount", { bankName: "Finsam MFB", accountName: "Test Account A", accountNumber: TEST_ACCT_A, initialBalance: 5000 }); const b = await apiKeyFetch("/api/createAccount", { bankName: "Finsam MFB", accountName: "Test Account B", accountNumber: TEST_ACCT_B, initialBalance: 0 }); out.textContent = `Account A [${a.status}]: ${JSON.stringify(a.data)}\n\nAccount B [${b.status}]: ${JSON.stringify(b.data)}`; } catch (e) { out.textContent = "Error: " + e.message; } } async function testLookup() { const out = document.getElementById("test-lookup-out"); out.textContent = "Running…"; try { const r = await apiKeyFetch("/api/lookupAccount", { accountNumber: TEST_ACCT_A }); out.textContent = `[${r.status}]: ${JSON.stringify(r.data)}`; } catch (e) { out.textContent = "Error: " + e.message; } } async function testTransfer() { const out = document.getElementById("test-transfer-out"); out.textContent = "Running…"; try { const r = await apiKeyFetch("/api/transferFunds", { fromAccount: TEST_ACCT_A, toAccount: TEST_ACCT_B, amount: 1000 }); out.textContent = `[${r.status}]: ${JSON.stringify(r.data)}`; } catch (e) { out.textContent = "Error: " + e.message; } } const TEST_USER_EMAIL = "customer@testapp.com"; const TEST_USER_PASSWORD = "testpass123"; let testUserToken = null; async function testAuthSignup() { const out = document.getElementById("test-authsignup-out"); out.textContent = "Running…"; try { const r = await apiKeyFetch("/api/auth/signup", { email: TEST_USER_EMAIL, password: TEST_USER_PASSWORD }); if (r.data.token) testUserToken = r.data.token; out.textContent = `[${r.status}]: ${JSON.stringify(r.data)}`; } catch (e) { out.textContent = "Error: " + e.message; } } async function testAuthLogin() { const out = document.getElementById("test-authlogin-out"); out.textContent = "Running…"; try { const r = await apiKeyFetch("/api/auth/login", { email: TEST_USER_EMAIL, password: TEST_USER_PASSWORD }); if (r.data.token) testUserToken = r.data.token; out.textContent = `[${r.status}]: ${JSON.stringify(r.data)}`; } catch (e) { out.textContent = "Error: " + e.message; } } async function testAuthMe() { const out = document.getElementById("test-authme-out"); if (!testUserToken) { out.textContent = "Run signup or login first to get a token."; return; } out.textContent = "Running…"; try { const apiKey = localStorage.getItem("finsam_apikey"); const res = await fetch(`${API_BASE}/api/auth/me`, { headers: { "x-api-key": apiKey, "Authorization": `Bearer ${testUserToken}` } }); const data = await res.json(); out.textContent = `[${res.status}]: ${JSON.stringify(data)}`; } catch (e) { out.textContent = "Error: " + e.message; } } // ---------- Messaging tests ---------- const TEST_USER2_EMAIL = "customer2@testapp.com"; const TEST_USER2_PASSWORD = "testpass456"; let testUser1Id = null, testUser2Id = null, testUser2Token = null, testConversationId = null; function apiKeyHeaders(extra) { const apiKey = localStorage.getItem("finsam_apikey"); return { "Content-Type": "application/json", "x-api-key": apiKey, ...(extra || {}) }; } async function testAuthSignup2() { const out = document.getElementById("test-authsignup2-out"); out.textContent = "Running…"; try { const res = await fetch(`${API_BASE}/api/auth/signup`, { method: "POST", headers: apiKeyHeaders(), body: JSON.stringify({ email: TEST_USER2_EMAIL, password: TEST_USER2_PASSWORD }) }); const data = await res.json(); if (data.userId) testUser2Id = data.userId; if (data.token) testUser2Token = data.token; if (testUserToken) { // decode user 1's id from earlier signup/login test if available } out.textContent = `[${res.status}]: ${JSON.stringify(data)}`; } catch (e) { out.textContent = "Error: " + e.message; } } async function testCreateConversation() { const out = document.getElementById("test-createconv-out"); if (!testUserToken || !testUser2Id) { out.textContent = "Run steps 4 (or 5) and 7 first to get both users."; return; } out.textContent = "Running…"; try { const res = await fetch(`${API_BASE}/api/messaging/createConversation`, { method: "POST", headers: apiKeyHeaders({ "Authorization": `Bearer ${testUserToken}` }), body: JSON.stringify({ type: "direct", memberUserIds: [testUser2Id] }) }); const data = await res.json(); if (data.conversationId) testConversationId = data.conversationId; out.textContent = `[${res.status}]: ${JSON.stringify(data)}`; } catch (e) { out.textContent = "Error: " + e.message; } } async function testSendMessage() { const out = document.getElementById("test-sendmsg-out"); if (!testUserToken || !testConversationId) { out.textContent = "Run step 8 first to create a conversation."; return; } out.textContent = "Running…"; try { const res = await fetch(`${API_BASE}/api/messaging/sendMessage`, { method: "POST", headers: apiKeyHeaders({ "Authorization": `Bearer ${testUserToken}` }), body: JSON.stringify({ conversationId: testConversationId, content: "Hey! This is a test message." }) }); const data = await res.json(); out.textContent = `[${res.status}]: ${JSON.stringify(data)}`; } catch (e) { out.textContent = "Error: " + e.message; } } async function testGetMessages() { const out = document.getElementById("test-getmsg-out"); if (!testUser2Token || !testConversationId) { out.textContent = "Run steps 7 and 8 first."; return; } out.textContent = "Running…"; try { const res = await fetch(`${API_BASE}/api/messaging/getMessages`, { method: "POST", headers: apiKeyHeaders({ "Authorization": `Bearer ${testUser2Token}` }), body: JSON.stringify({ conversationId: testConversationId, since: 0 }) }); const data = await res.json(); out.textContent = `[${res.status}]: ${JSON.stringify(data)}`; } catch (e) { out.textContent = "Error: " + e.message; } } async function testListConversations() { const out = document.getElementById("test-listconv-out"); if (!testUser2Token) { out.textContent = "Run step 7 first."; return; } out.textContent = "Running…"; try { const res = await fetch(`${API_BASE}/api/messaging/listConversations`, { method: "POST", headers: apiKeyHeaders({ "Authorization": `Bearer ${testUser2Token}` }), body: JSON.stringify({}) }); const data = await res.json(); out.textContent = `[${res.status}]: ${JSON.stringify(data)}`; } catch (e) { out.textContent = "Error: " + e.message; } } // auto-login if token exists window.addEventListener("load", () => { const token = localStorage.getItem("finsam_token"); if (token) enterConsole(); });