UNPKG

@scalar/api-client

Version:

the open source API testing client

402 lines (401 loc) 12.6 kB
import { isDefined as M } from "@scalar/helpers/array/is-defined"; import { sortByOrder as de } from "@scalar/helpers/array/sort-by-order"; import { migrateLocalStorageToIndexDb as ve } from "@scalar/oas-utils/migrations"; import { createSidebarState as fe, generateReverseIndex as he } from "@scalar/sidebar"; import { createWorkspaceStore as Y } from "@scalar/workspace-store/client"; import { createWorkspaceEventBus as we } from "@scalar/workspace-store/events"; import { generateUniqueValue as ge } from "@scalar/workspace-store/helpers/generate-unique-value"; import { getParentEntry as h } from "@scalar/workspace-store/navigation"; import { createWorkspaceStorePersistence as ke, getWorkspaceId as w } from "@scalar/workspace-store/persistence"; import { persistencePlugin as xe } from "@scalar/workspace-store/plugins/client"; import { extensions as be } from "@scalar/workspace-store/schemas/extensions"; import { ref as p, computed as u, shallowRef as j, readonly as ye } from "vue"; import { getRouteParam as l } from "./helpers/get-route-param.js"; import { groupWorkspacesByTeam as Se } from "./helpers/group-workspaces.js"; import { getActiveEnvironment as Ee } from "../../helpers/get-active-environment.js"; import { getTabDetails as We } from "../../helpers/get-tab-details.js"; import { slugify as Ue } from "../../helpers/slugify.js"; import { workspaceStorage as Te } from "../../helpers/storage.js"; import { initializeAppEventHandlers as Ie } from "./app-events.js"; import { filterWorkspacesByTeam as De, canLoadWorkspace as H } from "./helpers/filter-workspaces.js"; const Re = 1e3, Ae = 288, Xe = async ({ router: i, fileLoader: z }) => { const S = we({ debug: !1 }), { workspace: g } = await ke(); await ve(); const k = p("local"), f = p(void 0), x = p(void 0), E = p(void 0), B = p(void 0), L = p(void 0), N = p(void 0), W = p(!1); i.afterEach((e) => ue(e)); const d = u(() => i.currentRoute.value ?? null), U = j(null), v = p([]), b = u(() => De(v.value, k.value)), G = u(() => Se(b.value, k.value)), s = j(null), D = u(() => s.value?.workspace.documents[E.value ?? ""] || null), J = u(() => Ee(s.value, D.value)); v.value = await g.getAll().then( (e) => e.map(({ teamUid: a, namespace: t, slug: n, name: c }) => ({ id: w(t, n), teamUid: a, namespace: t, slug: n, label: c })) ); const Q = async (e) => { const a = f.value, t = x.value; if (!a || !t) return; const n = w(a, t); await g.updateName({ namespace: a, slug: t }, e) !== void 0 && (v.value = v.value.map((o) => o.id === n ? { ...o, label: e } : o), U.value = { id: n, label: e }); }, X = async ({ namespace: e, slug: a }) => Y({ plugins: [ await xe({ workspaceId: w(e, a), debounceDelay: Re }) ], fileLoader: z }), Z = async (e, a) => { const t = await g.getItem({ namespace: e, slug: a }); if (!t) return { success: !1 }; const n = await X({ namespace: e, slug: a }); return n.loadWorkspace(t.workspace), U.value = { id: w(t.namespace, t.slug), label: t.name }, s.value = n, { success: !0, workspace: n.workspace }; }, ee = async ({ name: e, teamUid: a, namespace: t, slug: n }) => { const c = Y(); await c.addDocument({ name: "drafts", document: { openapi: "3.1.0", info: { title: "Drafts", version: "1.0.0" }, paths: { "/": { get: {} } }, "x-scalar-original-document-hash": "drafts", "x-scalar-icon": "interface-edit-tool-pencil" } }); const o = await g.setItem( { namespace: t, slug: n }, { name: e, teamUid: a, workspace: c.exportWorkspace() } ); return v.value.push({ id: w(o.namespace, o.slug), teamUid: o.teamUid, namespace: o.namespace, slug: o.slug, label: o.name }), o; }, y = async (e, a) => { if (!e || !a) { await i.push("/"); return; } await i.push({ name: "example", params: { namespace: e, workspaceSlug: a, documentSlug: "drafts", pathEncoded: encodeURIComponent("/"), method: "get", exampleName: "default" } }); }, O = async ({ teamUid: e, namespace: a, slug: t, name: n }) => { s.value = null; const c = await ge({ defaultValue: t ?? n, // Use the provided id if it exists, otherwise use the name validation: async (I) => !await g.has({ namespace: a ?? "local", slug: I }), maxRetries: 100, transformation: Ue }); if (!c) return; const m = await ee({ teamUid: e, namespace: a, slug: c, name: n }); return await y(m.namespace, m.slug), m; }, ae = async (e, a) => { s.value = null, W.value = !0; const t = await Z(e, a); if (t.success) { const o = t.workspace["x-scalar-active-tab"] ?? 0, m = t.workspace["x-scalar-tabs"], I = m?.[o]; I && await i.replace({ path: I.path, query: d.value?.query ?? {} }), m && o >= m.length && S.emit("tabs:update:tabs", { "x-scalar-active-tab": 0 }), m || S.emit("tabs:update:tabs", { "x-scalar-tabs": [C(d.value)], "x-scalar-active-tab": 0 }), W.value = !1; return; } const n = b.value.find((o) => o.teamUid === "local" && o.slug === "default") ?? b.value[0]; if (n) return y(n.namespace, n.slug); const c = await O({ name: "Default Workspace", slug: "default" }); if (W.value = !1, !c) return console.error("Failed to create the default workspace, something went wrong, can not load the workspace"); r.reset(); }, te = (e) => { k.value = e; const a = b.value.find( (t) => t.namespace === f.value && t.slug === x.value ); if (!(a && H(a.teamUid, e))) return y("local", "default"); }, _ = u(() => { const e = s.value; if (!e) return []; const a = e.workspace["x-scalar-order"] ?? Object.keys(e.workspace.documents); return de(Object.keys(e.workspace.documents), a, (t) => t).map((t) => e.workspace.documents[t]?.["x-scalar-navigation"]).filter(M); }), r = fe(_), R = ({ document: e, path: a, method: t, example: n }) => JSON.stringify([e, a, t, n].filter(M)), P = u( () => he({ items: _.value, nestedKey: "children", filter: (e) => e.type === "document" || e.type === "operation" || e.type === "example", getId: (e) => { const a = h("document", e), t = h("operation", e); return R({ document: a?.name ?? "", path: t?.path, method: t?.method, example: e.type === "example" ? e.name : void 0 }); } }) ), T = (e) => { const a = P.value.get(R(e)); return a || P.value.get( R({ document: e.document, path: e.path, method: e.method }) ); }, V = (e) => { const a = r.getEntryById(e); if (!a) { console.warn(`Could not find sidebar entry with id ${e} to select`); return; } if (a.type === "document") { if (r.selectedItem.value === e) { r.setExpanded(e, !r.isExpanded(e)); return; } return r.setSelected(e), r.setExpanded(e, !0), i.push({ name: "document.overview", params: { documentSlug: a.name } }); } if (a.type === "operation") { if (r.isSelected(e)) { r.setExpanded(e, !r.isExpanded(e)); return; } const t = a.children?.find((n) => n.type === "example"); return t ? (r.setSelected(t.id), r.setExpanded(t.id, !0)) : r.setSelected(e), i.push({ name: "example", params: { documentSlug: h("document", a)?.name, pathEncoded: encodeURIComponent(a.path), method: a.method, exampleName: t?.name ?? "default" } }); } if (a.type === "example") { r.setSelected(e); const t = h("operation", a); return i.push({ name: "example", params: { documentSlug: h("document", a)?.name, pathEncoded: encodeURIComponent(t?.path ?? ""), method: t?.method, exampleName: a.name } }); } if (a.type === "text") return i.push({ name: "document.overview", params: { documentSlug: h("document", a)?.name } }); r.setExpanded(e, !r.isExpanded(e)); }, ne = async () => { if (!s.value) return; const e = s.value.workspace["x-scalar-active-tab"] ?? 0, a = s.value.workspace["x-scalar-tabs"]?.[e]; a && await i.replace(a.path); }, F = (e) => { e && s.value?.buildSidebar(e); }, se = (e) => { const a = D.value?.["x-scalar-navigation"]?.name; if (!a) return; const t = T({ document: a, path: e.path, method: e.method, example: e.exampleKey }); (!t || t.type !== "example") && (F(a), d.value && q(d.value)); }, oe = u(() => s.value?.workspace?.["x-scalar-sidebar-width"] ?? Ae), re = (e) => s.value?.update("x-scalar-sidebar-width", e), A = p(!0), ce = "x-scalar-tabs", le = "x-scalar-active-tab", C = (e) => { const a = l("method", e), t = l("pathEncoded", e), n = l("documentSlug", e), c = l("workspaceSlug", e); return { ...We({ workspace: c, document: n, path: t, method: a, getEntryByLocation: T }), path: d.value?.path ?? "" }; }, K = u(() => s.value?.workspace[ce] ?? [C(d.value)]), ie = u(() => s.value?.workspace[le] ?? 0), $ = async (e) => { const a = K.value[e]; if (!a) { console.warn(`Cannot copy URL: tab at index ${e} does not exist`); return; } const t = `${window.location.origin}${a.path}`; try { await navigator.clipboard.writeText(t); } catch (n) { console.error("Failed to copy URL to clipboard:", n); } }, ue = (e) => { const a = l("workspaceSlug", e), t = l("documentSlug", e), n = l("namespace", e); if (!n || !a) return; const c = v.value.find( (o) => o.slug === a && o.namespace === n ); if (c && !H(c.teamUid, k.value)) return y("local", "default"); if (f.value = n, x.value = a, E.value = t, B.value = l("method", e), L.value = l("pathEncoded", e), N.value = l("exampleName", e), e.path !== "" && Te.setCurrentPath(e.path), w(f.value, a) !== U.value?.id) return ae(f.value, a); t && t !== s.value?.workspace[be.workspace.activeDocument] && s?.value?.update("x-scalar-active-document", t), pe(e), q(e); }, pe = (e) => { const a = s.value?.workspace["x-scalar-tabs"] ?? [], t = s.value?.workspace["x-scalar-active-tab"] ?? 0, n = a[t]; !n || n.path === e.path || (a[t] = C(e)); }, q = (e) => { const a = l("documentSlug", e); if (!a) { r.setSelected(null); return; } const t = T({ document: a, path: l("pathEncoded", e), method: l("method", e), example: l("exampleName", e) }); t && (r.setSelected(t.id), r.setExpanded(t.id, !0)); }; Ie({ eventBus: S, router: i, store: s, navigateToCurrentTab: ne, rebuildSidebar: F, onAfterExampleCreation: se, onSelectSidebarItem: V, onCopyTabUrl: (e) => $(e), onToggleSidebar: () => A.value = !A.value, renameWorkspace: Q }); const me = u(() => { const e = s.value?.workspace["x-scalar-color-mode"] ?? "system"; return e === "system" ? window.matchMedia?.("(prefers-color-scheme: dark)")?.matches ?? !1 : e === "dark"; }); return { /** Active workspace store */ store: s, sidebar: { state: r, width: oe, isOpen: A, handleSelectItem: V, handleSidebarWidthUpdate: re, getEntryByLocation: T }, tabs: { state: K, activeTabIndex: ie, copyTabUrl: $ }, workspace: { create: O, workspaceList: v, filteredWorkspaceList: b, workspaceGroups: G, activeWorkspace: U, navigateToWorkspace: y, isOpen: u(() => !!(x.value && !E.value)) }, eventBus: S, router: i, currentRoute: d, loading: W, activeEntities: { namespace: f, workspaceSlug: x, documentSlug: E, path: L, method: B, exampleName: N, teamUid: ye(k), setTeamUid: te }, environment: J, document: D, isDarkMode: me }; }; export { Xe as createAppState };