PageSourceSearch

https://xagent.id/assets/dashboard-client.js

js xagent.id collected 2026-10-05 06:32:49 UTC 4,467 bytes, 116 lines download raw bytes

1(function attachDashboardClient(root) {
2  "use strict";
3
4  function normalizeHost(value) {
5    const raw = String(value || "").trim();
6    if (!raw) return "";
7    try {
8      const parsed = new URL(raw.includes("://") ? raw : `https://${raw}`);
9      return parsed.hostname.toLowerCase().replace(/\.$/, "");
10    } catch (_error) {
11      return "";
12    }
13  }
14
15  function dashboardSitePath(route, host) {
16    return `/api/dashboard/${route}?url=${encodeURIComponent(`https://${host}`)}`;
17  }
18
19  function createDashboardClient(options) {
20    const request = options && options.request;
21    if (typeof request !== "function") throw new TypeError("dashboard_request_required");
22    let allowedSites = new Map();
23    let generation = 0;
24    const stale = () => Object.assign(new Error("dashboard_request_superseded"), {code: "dashboard_request_superseded"});
25
26    function publicSites() {
27      return [...allowedSites.values()].map((site) => ({...site}));
28    }
29
30    async function loadSite(value) {
31      const epoch = ++generation;
32      const host = normalizeHost(value);
33      if (!host || !allowedSites.has(host)) {
34        const error = new Error("dashboard_site_not_authorized");
35        error.code = "dashboard_site_not_authorized";
36        throw error;
37      }
38      const scoped = async (route) => {
39        try {
40          const result = await request(dashboardSitePath(route, host), {cache: "no-store"});
41          if (epoch !== generation) throw stale();
42          const returnedHost = normalizeHost(result?.host || result?.customer?.host);
43          if ((route === "data" && !returnedHost) || (returnedHost && returnedHost !== host)) {
44            throw new Error("dashboard_response_subject_mismatch");
45          }
46          return result;
47        } catch (error) {
48          if (epoch !== generation) throw stale();
49          if (error.status === 401) { allowedSites.clear(); generation++; }
50          throw error;
51        }
52      };
53      const data = await scoped("data");
54      const connectors = await scoped("connectors");
55      const tasks = await scoped("tasks");
56      const billing = await scoped("billing");
57      const decision = await scoped("decision");
58      return {host, data, connectors, tasks, billing, decision};
59    }
60
61    async function bootstrap(pathname, requestedSite) {
62      allowedSites.clear();
63      generation++;
64      const normalizedPath = String(pathname || "").replace(/\/+$/, "") || "/";
65      if (normalizedPath === "/dashboard/demo") {
66        const data = await request("/api/demo/dashboard");
67        return {mode: "demo", selectedHost: normalizeHost(data?.customer?.host) || "xagent.id", data};
68      }
69      try {
70        await request("/api/dashboard/session");
71      } catch (error) {
72        if (error && (error.status === 401 || String(error.message || "").includes("dashboard_session_invalid_or_expired"))) {
73          allowedSites = new Map();
74          return {mode: "login_required", reason: "dashboard_session_invalid_or_expired", sites: []};
75        }
76        throw error;
77      }
78      const payload = await request("/api/dashboard/sites");
79      allowedSites = new Map();
80      for (const item of payload?.sites || []) {
81        const host = normalizeHost(item?.host);
82        if (host && !allowedSites.has(host)) allowedSites.set(host, {...item, host});
83      }
84      if (!allowedSites.size) {
85        const error = new Error("dashboard_has_no_linked_sites");
86        error.code = "dashboard_has_no_linked_sites";
87        throw error;
88      }
89      const requestedHost = normalizeHost(requestedSite);
90      const requestedSiteRejected = Boolean(requestedHost && !allowedSites.has(requestedHost));
91      const selectedHost = requestedHost && allowedSites.has(requestedHost)
92        ? requestedHost
93        : allowedSites.keys().next().value;
94      const bundle = await loadSite(selectedHost);
95      return {
96        mode: "customer",
97        sites: publicSites(),
98        selectedHost,
99        requestedSiteRejected,
100        bundle,
101      };
102    }
103
104    async function logout() {
105      allowedSites = new Map();
106      generation++;
107      return request("/api/dashboard/logout", {method: "POST"});
108    }
109
110    return {bootstrap, loadSite, logout, sites: publicSites};
111  }
112
113  const api = {createDashboardClient, normalizeHost};
114  if (typeof module === "object" && module.exports) module.exports = api;
115  if (root) root.AgentIdDashboardClient = api;
116})(typeof window !== "undefined" ? window : globalThis);

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.