From db63dbb9e471c8753416d2dddcc9e4d052016e32 Mon Sep 17 00:00:00 2001 From: Andreas Molnar Date: Fri, 28 Aug 2026 20:15:16 +0200 Subject: [PATCH 1/3] feat: add identifiable client sessions --- apps/backend/openapi.yaml | 24 +++ apps/backend/src/index.ts | 33 ++++- apps/backend/src/lib/data/auth.ts | 1 + apps/backend/src/lib/data/sessions.ts | 125 ++++++++++++++++ apps/backend/src/routes/auth.route.ts | 2 +- apps/backend/src/routes/sessions.route.ts | 27 ++++ apps/backend/src/routes/shared.ts | 19 ++- apps/web/public/openapi.json | 39 +++++ .../(authenticated)/settings/account/page.tsx | 64 +++++++- .../monitoring/ssh/SshSessionsProvider.tsx | 3 + .../monitoring/useMonitoringHostMetrics.ts | 3 + apps/web/src/context/ActivityContext.tsx | 9 +- apps/web/src/context/useAuth.tsx | 3 +- apps/web/src/lib/api/index.ts | 4 +- apps/web/src/lib/api/sdk.gen.ts | 19 ++- apps/web/src/lib/api/types.gen.ts | 54 +++++++ apps/web/src/lib/apiClient.ts | 42 +++++- apps/web/src/lib/queryClient.ts | 1 + apps/web/src/lib/rpcClient.ts | 7 +- apps/web/src/lib/session.ts | 36 +++++ packages/api-types/src/openapi.ts | 43 ++++++ packages/types/pocketbase/pocketbase-types.ts | 16 ++ packages/types/sdk-types.ts | 1 + .../migrations/1785000003_created_sessions.js | 138 ++++++++++++++++++ 24 files changed, 693 insertions(+), 20 deletions(-) create mode 100644 apps/backend/src/lib/data/sessions.ts create mode 100644 apps/backend/src/routes/sessions.route.ts create mode 100644 apps/web/src/lib/session.ts create mode 100644 pocketbase/migrations/1785000003_created_sessions.js diff --git a/apps/backend/openapi.yaml b/apps/backend/openapi.yaml index 58c74c7e..c1eb2f8e 100644 --- a/apps/backend/openapi.yaml +++ b/apps/backend/openapi.yaml @@ -18,6 +18,7 @@ tags: - name: notifications - name: pageConfig - name: search + - name: sessions - name: test - name: wallpapers - name: widgets @@ -167,6 +168,29 @@ paths: $ref: "#/components/responses/JsonOk" "401": $ref: "#/components/responses/JsonUnauthorized" + /sessions/current: + get: + tags: + - sessions + summary: Get the current client session + responses: + "200": + $ref: "#/components/responses/JsonOk" + "401": + $ref: "#/components/responses/JsonUnauthorized" + patch: + tags: + - sessions + summary: Rename the current client session + requestBody: + $ref: "#/components/requestBodies/JsonBody" + responses: + "200": + $ref: "#/components/responses/JsonOk" + "400": + $ref: "#/components/responses/JsonBadRequest" + "401": + $ref: "#/components/responses/JsonUnauthorized" /integrations: get: tags: diff --git a/apps/backend/src/index.ts b/apps/backend/src/index.ts index fedaacb0..12941bdf 100644 --- a/apps/backend/src/index.ts +++ b/apps/backend/src/index.ts @@ -7,6 +7,7 @@ import { Client as SshClient } from "ssh2"; import { config } from "./lib/config"; import { subscribeActivity } from "./lib/activity"; +import { ensureSession } from "./lib/data/sessions"; import { jobsApi, registerJobsCron } from "./jobs/index"; import { startPocketbase } from "./pocketbase"; import { createLogger } from "./lib/logger"; @@ -15,8 +16,9 @@ import { getNotifications } from "./lib/data/notifications/items"; import { listIntegrations } from "./lib/data/integrations"; import { getUpcomingEvents } from "./lib/calendar"; import { systemAgentClient } from "./lib/systemAgent"; -import { requireAuth } from "./routes/shared"; +import { readAuth, readSessionMetadata, requireAuth } from "./routes/shared"; import authRoute from "./routes/auth.route"; +import sessionsRoute from "./routes/sessions.route"; import systemRoute from "./routes/system.route"; import dataRoute from "./routes/data.route"; @@ -64,7 +66,24 @@ app.use("*", async (c, next) => { app.use("*", cors({ origin: "*" })); +// Session identity is deliberately independent from the auth token. Touch the +// current device on every authenticated API request that carries its stable id. +app.use("/api/v1/*", async (c, next) => { + const auth = readAuth(c); + if (auth.token && auth.sessionId) { + try { + const { pb, userId } = await requireAuth(auth); + await ensureSession(pb, userId, auth.sessionId, readSessionMetadata(c)); + } catch { + // The route handler remains responsible for returning auth errors. This + // middleware should not turn a missing/expired session touch into one. + } + } + await next(); +}); + app.route("/", authRoute); +app.route("/", sessionsRoute); app.route("/", systemRoute); app.route("/", dataRoute); @@ -77,8 +96,10 @@ app.get("/api/v1/activity", upgradeWebSocket((c) => { return { async onOpen(_event, ws) { const token = c.req.query("token") || ""; + const sessionId = c.req.query("sessionId") || c.req.header("x-session-id") || null; try { - const { userId, pb } = await requireAuth({ token }); + const { userId, pb } = await requireAuth({ token, sessionId }); + await ensureSession(pb, userId, sessionId, readSessionMetadata(c)); const sendSnapshot = async () => { const [notificationResult, integrationResult] = await Promise.all([ getNotifications(userId), @@ -143,10 +164,12 @@ app.get("/api/v1/monitoring/ssh-hosts/:id/console", upgradeWebSocket((c) => { return { async onOpen(_event, ws) { const token = c.req.query("token") || c.req.header("Authorization")?.replace(/^Bearer\s+/i, "") || ""; + const sessionId = c.req.query("sessionId") || c.req.header("x-session-id") || null; const hostId = c.req.param("id") || ""; try { - const { userId } = await requireAuth({ token }); + const { userId, pb } = await requireAuth({ token, sessionId }); + await ensureSession(pb, userId, sessionId, readSessionMetadata(c)); const host = await getMonitoringSshHostById(userId, hostId); if (!host) { ws.send(JSON.stringify({ type: "error", message: "SSH host not found" })); @@ -232,8 +255,10 @@ app.get("/api/v1/monitoring/hosts/:id/stats/live", upgradeWebSocket((c) => { return { async onOpen(_event, ws) { const token = c.req.query("token") || c.req.header("Authorization")?.replace(/^Bearer\s+/i, "") || ""; + const sessionId = c.req.query("sessionId") || c.req.header("x-session-id") || null; try { - const { userId } = await requireAuth({ token }); + const { userId, pb } = await requireAuth({ token, sessionId }); + await ensureSession(pb, userId, sessionId, readSessionMetadata(c)); const host = await getSystemAgentHostById(userId, c.req.param("id") || ""); if (!host) { ws.close(1008, "Monitoring host not found"); diff --git a/apps/backend/src/lib/data/auth.ts b/apps/backend/src/lib/data/auth.ts index e864872b..f4a5808e 100644 --- a/apps/backend/src/lib/data/auth.ts +++ b/apps/backend/src/lib/data/auth.ts @@ -18,6 +18,7 @@ export class ApiActionError extends Error { export type ActionAuth = { token?: string | null; + sessionId?: string | null; }; export type JsonPrimitive = string | number | boolean | null; diff --git a/apps/backend/src/lib/data/sessions.ts b/apps/backend/src/lib/data/sessions.ts new file mode 100644 index 00000000..04e677e7 --- /dev/null +++ b/apps/backend/src/lib/data/sessions.ts @@ -0,0 +1,125 @@ +import type { RecordModel } from "pocketbase"; + +import { ApiActionError } from "./auth"; + +export type SessionRecord = { + id: string; + user: string; + sessionId: string; + displayName: string; + clientType?: string; + platform?: string; + lastSeenAt: string; + created?: string; + updated?: string; +}; + +type SessionMetadata = { + clientType?: string; + platform?: string; +}; + +const SESSION_ID_PATTERN = /^[A-Za-z0-9][A-Za-z0-9_-]{0,127}$/; +const DEFAULT_DISPLAY_NAME = "Web browser"; + +export function normalizeSessionId(value: unknown) { + const sessionId = typeof value === "string" ? value.trim() : ""; + return SESSION_ID_PATTERN.test(sessionId) ? sessionId : null; +} + +function normalizeMetadata(metadata?: SessionMetadata) { + return { + ...(metadata?.clientType?.trim() ? { clientType: metadata.clientType.trim().slice(0, 100) } : {}), + ...(metadata?.platform?.trim() ? { platform: metadata.platform.trim().slice(0, 100) } : {}), + }; +} + +function toSessionRecord(record: RecordModel) { + return record as unknown as SessionRecord; +} + +export async function ensureSession( + pb: { collection: (name: "sessions") => any }, + userId: string, + rawSessionId: unknown, + metadata?: SessionMetadata, +) { + const sessionId = normalizeSessionId(rawSessionId); + if (!sessionId) return null; + + const now = new Date().toISOString(); + const collection = pb.collection("sessions"); + const filter = `user = "${userId}" && sessionId = "${sessionId}"`; + const normalizedMetadata = normalizeMetadata(metadata); + + let session: RecordModel | null = null; + try { + session = await collection.getFirstListItem(filter); + } catch { + // A missing record is created below. Other read errors are surfaced by create/update. + } + + if (session) { + return toSessionRecord(await collection.update(session.id, { + lastSeenAt: now, + ...normalizedMetadata, + })); + } + + try { + return toSessionRecord(await collection.create({ + user: userId, + sessionId, + displayName: DEFAULT_DISPLAY_NAME, + lastSeenAt: now, + ...normalizedMetadata, + })); + } catch (error) { + // Another request from the same client may have won the race to create the unique pair. + try { + const existing = await collection.getFirstListItem(filter); + return toSessionRecord(await collection.update(existing.id, { + lastSeenAt: now, + ...normalizedMetadata, + })); + } catch { + throw error; + } + } +} + +export async function getCurrentSession( + pb: { collection: (name: "sessions") => any }, + userId: string, + rawSessionId: unknown, + metadata?: SessionMetadata, +) { + const session = await ensureSession(pb, userId, rawSessionId, metadata); + if (!session) { + throw new ApiActionError("A valid session id is required", 400, { + error: "A valid session id is required", + }); + } + return session; +} + +export async function renameCurrentSession( + pb: { collection: (name: "sessions") => any }, + userId: string, + rawSessionId: unknown, + displayName: unknown, + metadata?: SessionMetadata, +) { + const session = await getCurrentSession(pb, userId, rawSessionId, metadata); + const normalizedName = typeof displayName === "string" ? displayName.trim() : ""; + if (!normalizedName || normalizedName.length > 100) { + throw new ApiActionError("Display name must be between 1 and 100 characters", 400, { + error: "Display name must be between 1 and 100 characters", + }); + } + + return toSessionRecord(await pb.collection("sessions").update(session.id, { + displayName: normalizedName, + lastSeenAt: new Date().toISOString(), + })); +} diff --git a/apps/backend/src/routes/auth.route.ts b/apps/backend/src/routes/auth.route.ts index dc71dc7f..7dd61134 100644 --- a/apps/backend/src/routes/auth.route.ts +++ b/apps/backend/src/routes/auth.route.ts @@ -122,7 +122,7 @@ authRoute.get( "/api/v1/auth/validate-auth", withJson(async (c) => { const body = await readJsonBody< - { token?: string; auth?: { token?: string | null } } + { token?: string; auth?: { token?: string | null; sessionId?: string | null } } >(c); return validateAuthToken(String(body?.token ?? body?.auth?.token ?? "")); }), diff --git a/apps/backend/src/routes/sessions.route.ts b/apps/backend/src/routes/sessions.route.ts new file mode 100644 index 00000000..948c179d --- /dev/null +++ b/apps/backend/src/routes/sessions.route.ts @@ -0,0 +1,27 @@ +import { Hono } from "hono"; + +import { getCurrentSession, renameCurrentSession } from "../lib/data/sessions"; +import { readAuth, readJsonBody, readSessionMetadata, requireAuth, withJson } from "./shared"; + +const sessionsRoute = new Hono(); + +sessionsRoute + .get("/api/v1/sessions/current", withJson(async (c) => { + const requestAuth = readAuth(c); + const auth = await requireAuth(requestAuth); + return getCurrentSession(auth.pb, auth.userId, requestAuth.sessionId, readSessionMetadata(c)); + })) + .patch("/api/v1/sessions/current", withJson(async (c) => { + const body = await readJsonBody<{ displayName?: unknown }>(c); + const requestAuth = readAuth(c); + const auth = await requireAuth(requestAuth); + return renameCurrentSession( + auth.pb, + auth.userId, + requestAuth.sessionId, + body.displayName, + readSessionMetadata(c), + ); + })); + +export default sessionsRoute; diff --git a/apps/backend/src/routes/shared.ts b/apps/backend/src/routes/shared.ts index 662c4e06..ab534d2c 100644 --- a/apps/backend/src/routes/shared.ts +++ b/apps/backend/src/routes/shared.ts @@ -17,7 +17,10 @@ import { defaultHomeConfig } from "@dashwise/assets"; export type JsonHandler) = import("hono").Context> = (c: C) => Promise | unknown; -export const authInput = z.object({ token: z.string().nullable().optional() }); +export const authInput = z.object({ + token: z.string().nullable().optional(), + sessionId: z.string().nullable().optional(), +}); export function normalizePageName(pageName?: string | null) { const cleaned = String(pageName ?? "home").trim().toLowerCase(); @@ -106,6 +109,20 @@ export function readAuthToken(c: Context) { return c.req.query("token") ?? c.req.query("authToken") ?? null; } +export function readAuth(c: Context) { + return { + token: readAuthToken(c), + sessionId: c.req.header("x-session-id") ?? null, + }; +} + +export function readSessionMetadata(c: Context) { + return { + clientType: c.req.header("x-client-type") ?? undefined, + platform: c.req.header("x-platform") ?? undefined, + }; +} + export async function readJsonBody>(c: Context): Promise { try { return await c.req.json(); diff --git a/apps/web/public/openapi.json b/apps/web/public/openapi.json index cbe438b4..5e7ba5ad 100644 --- a/apps/web/public/openapi.json +++ b/apps/web/public/openapi.json @@ -47,6 +47,9 @@ { "name": "search" }, + { + "name": "sessions" + }, { "name": "test" }, @@ -284,6 +287,42 @@ } } }, + "/sessions/current": { + "get": { + "tags": [ + "sessions" + ], + "summary": "Get the current client session", + "responses": { + "200": { + "$ref": "#/components/responses/JsonOk" + }, + "401": { + "$ref": "#/components/responses/JsonUnauthorized" + } + } + }, + "patch": { + "tags": [ + "sessions" + ], + "summary": "Rename the current client session", + "requestBody": { + "$ref": "#/components/requestBodies/JsonBody" + }, + "responses": { + "200": { + "$ref": "#/components/responses/JsonOk" + }, + "400": { + "$ref": "#/components/responses/JsonBadRequest" + }, + "401": { + "$ref": "#/components/responses/JsonUnauthorized" + } + } + } + }, "/integrations": { "get": { "tags": [ diff --git a/apps/web/src/app/(authenticated)/settings/account/page.tsx b/apps/web/src/app/(authenticated)/settings/account/page.tsx index b105dcdc..332bb882 100644 --- a/apps/web/src/app/(authenticated)/settings/account/page.tsx +++ b/apps/web/src/app/(authenticated)/settings/account/page.tsx @@ -1,5 +1,5 @@ -import React, { useState } from "react"; +import React, { useEffect, useState } from "react"; import { Dialog, DialogClose, @@ -17,12 +17,15 @@ import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert"; import { ChangePasswordRequest } from '@/lib/apiClient'; import { useNavigate } from "react-router-dom"; import { changePasswordAction, deleteAccountAction } from '@/lib/apiClient'; +import { getCurrentSessionAction, renameCurrentSessionAction } from '@/lib/apiClient'; import { DialogDescription } from "@radix-ui/react-dialog"; import useAuth from "@/context/useAuth"; +import { useMutation, useQuery } from "@tanstack/react-query"; +import { queryKeys } from "@/lib/queryClient"; export default function AccountSettingsPage() { const navigate = useNavigate(); - const { user, token, setAuth, logout } = useAuth(); + const { user, token, setAuth, logout, withAuth } = useAuth(); const [oldPassword, setOldPassword] = useState(""); const [newPassword, setNewPassword] = useState(""); const [confirmPassword, setConfirmPassword] = useState(""); @@ -33,6 +36,38 @@ export default function AccountSettingsPage() { const [deleteTotp, setDeleteTotp] = useState(""); const [deleteLoading, setDeleteLoading] = useState(false); const [deleteError, setDeleteError] = useState(null); + const [sessionName, setSessionName] = useState(""); + const [sessionError, setSessionError] = useState(null); + const sessionQuery = useQuery({ + queryKey: queryKeys.auth.session(token), + enabled: Boolean(token), + retry: false, + queryFn: () => withAuth(getCurrentSessionAction), + }); + const sessionMutation = useMutation({ + mutationFn: (displayName: string) => withAuth((auth) => renameCurrentSessionAction(auth, displayName)), + onSuccess: (session) => { + setSessionName(session.displayName); + setSessionError(null); + }, + }); + + useEffect(() => { + if (sessionQuery.data?.displayName) setSessionName(sessionQuery.data.displayName); + }, [sessionQuery.data?.displayName]); + + const handleSessionNameSubmit = (event: React.FormEvent) => { + event.preventDefault(); + const normalizedName = sessionName.trim(); + if (!normalizedName || normalizedName.length > 100) { + setSessionError("device name must be between 1 and 100 characters"); + return; + } + setSessionError(null); + sessionMutation.mutate(normalizedName, { + onError: (cause) => setSessionError(cause instanceof Error ? cause.message : "failed to save device name"), + }); + }; const handleChangePasswordSubmit = async ( e: React.FormEvent, @@ -142,6 +177,31 @@ export default function AccountSettingsPage() { {user?.name ?? "Lorem ipsum"} +
+
+ +
+

device

+

name this browser so you can recognize it elsewhere in dashwise.

+
+
+
+ + setSessionName(event.target.value)} + placeholder="web browser" + maxLength={100} + disabled={sessionQuery.isLoading || sessionMutation.isPending} + /> + +
+ {sessionError &&

{sessionError}

} +
+

Authentication

diff --git a/apps/web/src/components/monitoring/ssh/SshSessionsProvider.tsx b/apps/web/src/components/monitoring/ssh/SshSessionsProvider.tsx index caad41ff..c25918d9 100644 --- a/apps/web/src/components/monitoring/ssh/SshSessionsProvider.tsx +++ b/apps/web/src/components/monitoring/ssh/SshSessionsProvider.tsx @@ -16,6 +16,7 @@ import { FitAddon } from "xterm-addon-fit"; import useAuth from "@/context/useAuth"; import { backendUrl, type MonitoringSshHostRecord } from "@/lib/apiClient"; +import { getClientSessionId } from "@/lib/session"; import config from "@/lib/config"; import "xterm/css/xterm.css"; @@ -107,6 +108,8 @@ function SshTerminalSession( ); url.protocol = url.protocol === "https:" ? "wss:" : "ws:"; url.searchParams.set("token", token); + const sessionId = getClientSessionId(); + if (sessionId) url.searchParams.set("sessionId", sessionId); const socket = new WebSocket(url.toString()); wsRef.current = socket; diff --git a/apps/web/src/components/monitoring/useMonitoringHostMetrics.ts b/apps/web/src/components/monitoring/useMonitoringHostMetrics.ts index e0b235e5..3913d618 100644 --- a/apps/web/src/components/monitoring/useMonitoringHostMetrics.ts +++ b/apps/web/src/components/monitoring/useMonitoringHostMetrics.ts @@ -7,6 +7,7 @@ import { getMonitoringHostHistoryAction, type MonitoringHostStatsRecord, } from "@/lib/apiClient"; +import { getClientSessionId } from "@/lib/session"; export type HostMetricRecord = MonitoringHostStatsRecord & { time: string; @@ -99,6 +100,8 @@ export function useMonitoringHostMetrics(hostId?: string) { const url = new URL(backendUrl(`/api/v1/monitoring/hosts/${hostId}/stats/live`)); url.protocol = url.protocol === "https:" ? "wss:" : "ws:"; url.searchParams.set("token", token); + const sessionId = getClientSessionId(); + if (sessionId) url.searchParams.set("sessionId", sessionId); if (latestRef.current) url.searchParams.set("since", latestRef.current); socket = new WebSocket(url.toString()); diff --git a/apps/web/src/context/ActivityContext.tsx b/apps/web/src/context/ActivityContext.tsx index d8d2a81e..d3963a1e 100644 --- a/apps/web/src/context/ActivityContext.tsx +++ b/apps/web/src/context/ActivityContext.tsx @@ -5,6 +5,7 @@ import useAuth from "@/context/useAuth"; import { backendUrl } from "@/lib/apiClient"; import { useQueryClient } from "@tanstack/react-query"; import { queryKeys } from "@/lib/queryClient"; +import { getClientSessionId } from "@/lib/session"; export type ActivityNotification = { id: string; @@ -34,15 +35,17 @@ type ActivityContextValue = { const ActivityContext = createContext(null); -function socketUrl(token: string) { +function socketUrl(token: string, sessionId: string | null) { const url = new URL(backendUrl("api/v1/activity")); url.protocol = url.protocol === "https:" ? "wss:" : "ws:"; url.searchParams.set("token", token); + if (sessionId) url.searchParams.set("sessionId", sessionId); return url.toString(); } export function ActivityProvider({ children }: { children: ReactNode }) { const { token } = useAuth(); + const sessionId = getClientSessionId(); const queryClient = useQueryClient(); const socket = useRef(null); const reconnectTimer = useRef(null); @@ -59,7 +62,7 @@ export function ActivityProvider({ children }: { children: ReactNode }) { let closed = false; const connect = () => { - const nextSocket = new WebSocket(socketUrl(token)); + const nextSocket = new WebSocket(socketUrl(token, sessionId)); socket.current = nextSocket; nextSocket.onopen = () => nextSocket.send(JSON.stringify({ type: "activity:subscribe" })); nextSocket.onmessage = (event) => { @@ -86,7 +89,7 @@ export function ActivityProvider({ children }: { children: ReactNode }) { socket.current?.close(); socket.current = null; }; - }, [queryClient, token]); + }, [queryClient, sessionId, token]); const refresh = () => { if (socket.current?.readyState === WebSocket.OPEN) { diff --git a/apps/web/src/context/useAuth.tsx b/apps/web/src/context/useAuth.tsx index 5938f6a9..356485ca 100644 --- a/apps/web/src/context/useAuth.tsx +++ b/apps/web/src/context/useAuth.tsx @@ -1,6 +1,7 @@ "use client" import { updateUserPropertyAction } from '@/lib/apiClient'; +import { getClientSessionId } from "@/lib/session"; import type { ActionAuth, AuthUserRecord, UserPropertyValue } from "@dashwise/types/sdk"; import { useCallback, useEffect, useState } from "react"; import { useNavigate } from "react-router-dom"; @@ -143,7 +144,7 @@ export function useAuth() { throw createUnauthorizedError(); } try { - return await fn({ token }); + return await fn({ token, sessionId: getClientSessionId() }); } catch (err: unknown) { if (typeof err === "object" && err !== null && "status" in err && (err as { status?: number }).status === 401) { onUnauthorized?.(); diff --git a/apps/web/src/lib/api/index.ts b/apps/web/src/lib/api/index.ts index 855dd790..313e7054 100644 --- a/apps/web/src/lib/api/index.ts +++ b/apps/web/src/lib/api/index.ts @@ -1,5 +1,5 @@ // DO NOT EDIT — generated by bun run generate // This file is auto-generated by @hey-api/openapi-ts -export { deleteAuthDeleteAccount, deleteIntegrationsById, deleteLinksItemsByLinkId, deleteMonitoringHostsById, deleteMonitoringSshHostsById, deleteMonitorsById, deleteNewsFeedRecordsById, deleteNotificationsForwarders, deleteNotificationsTopics, deleteNotificationsTopicTokens, getAppConfig, getAppInfo, getAuthCallback, getAuthSso, getGlanceables, getGlanceablesByIntegration, getIntegrations, getIntegrationsCaldavEvents, getIntegrationsConsumerData, getIntegrationsWidgetProperties, getJobsPullIcons, getJobsSearchItems, getLinksCollections, getLinksFolders, getLinksHome, getLinksHomeGroups, getLinksItems, getLinksTags, getLocations, getMonitoringHosts, getMonitoringHostsById, getMonitoringHostsByIdHistory, getMonitoringHostsByIdStats, getMonitoringSshHosts, getMonitoringStatus, getMonitors, getMonitorsById, getNews, getNewsFeed, getNewsFeedMetadata, getNewsFeedRecordsById, getNewsFeedRefresh, getNewsFeeds, getNewsFeedsById, getNewsSubscriptions, getNewsSubscriptionsByIdJson, getNotifications, getNotificationsForwarders, getNotificationsTopics, getNotificationsTopicTokens, getPageConfig, getPageConfigUserPages, getSearchItems, getSearchItemsFrequentlyUsed, getTestBookmarks, getWallpapers, getWeather, getWidgets, getWidgetsByIntegration, getWidgetsGlanceable, getWidgetsGlanceables, type Options, patchAuthUpdateUserProperty, postAuthChangePassword, postAuthLogin, postAuthMfa, postAuthSignup, postAuthValidateAuth, postIntegrations, postIntegrationsConsumerData, postIntegrationsProxyAction, postIntegrationsTestEndpoint, postLinksCollections, postLinksFolders, postLinksHomeGroups, postLinksItems, postLinksReorder, postLinksTags, postMonitoringHosts, postMonitoringHostsByIdRefresh, postMonitoringSshHosts, postMonitoringStatus, postMonitors, postNewsFeedRecords, postNewsFeedRecordsById, postNewsFeedRefresh, postNewsFeedSubscribe, postNewsFeedUnsubscribe, postNewsFeedUpdate, postNewsFixMissingTitles, postNotifications, postNotificationsByTopic, postNotificationsForwarders, postNotificationsForwardersTest, postNotificationsMarkAsRead, postNotificationsTest, postNotificationsTopics, postNotificationsTopicTokens, postPageConfigHome, postPageConfigIntegrationData, postPageConfigMigrateLegacy, postSearchItemsUsageStats, postWallpapers, putIntegrationsById, putLinksCollectionsByCollectionId, putLinksFoldersByFolderIdIcon, putLinksItemsByLinkId, putLinksTagsByTagId, putMonitoringHostsById, putMonitoringSshHostsById, putMonitorsById, putNotificationsForwarders, putNotificationsTopicTokens, putPageConfig } from './sdk.gen'; -export type { ClientOptions, DeleteAuthDeleteAccountData, DeleteAuthDeleteAccountError, DeleteAuthDeleteAccountErrors, DeleteAuthDeleteAccountResponse, DeleteAuthDeleteAccountResponses, DeleteIntegrationsByIdData, DeleteIntegrationsByIdResponse, DeleteIntegrationsByIdResponses, DeleteLinksItemsByLinkIdData, DeleteLinksItemsByLinkIdResponse, DeleteLinksItemsByLinkIdResponses, DeleteMonitoringHostsByIdData, DeleteMonitoringHostsByIdResponse, DeleteMonitoringHostsByIdResponses, DeleteMonitoringSshHostsByIdData, DeleteMonitoringSshHostsByIdResponse, DeleteMonitoringSshHostsByIdResponses, DeleteMonitorsByIdData, DeleteMonitorsByIdResponse, DeleteMonitorsByIdResponses, DeleteNewsFeedRecordsByIdData, DeleteNewsFeedRecordsByIdResponse, DeleteNewsFeedRecordsByIdResponses, DeleteNotificationsForwardersData, DeleteNotificationsForwardersResponse, DeleteNotificationsForwardersResponses, DeleteNotificationsTopicsData, DeleteNotificationsTopicsResponse, DeleteNotificationsTopicsResponses, DeleteNotificationsTopicTokensData, DeleteNotificationsTopicTokensResponse, DeleteNotificationsTopicTokensResponses, Error, GenericObject, GetAppConfigData, GetAppConfigResponse, GetAppConfigResponses, GetAppInfoData, GetAppInfoResponse, GetAppInfoResponses, GetAuthCallbackData, GetAuthCallbackResponse, GetAuthCallbackResponses, GetAuthSsoData, GetAuthSsoResponse, GetAuthSsoResponses, GetGlanceablesByIntegrationData, GetGlanceablesByIntegrationResponse, GetGlanceablesByIntegrationResponses, GetGlanceablesData, GetGlanceablesResponse, GetGlanceablesResponses, GetIntegrationsCaldavEventsData, GetIntegrationsCaldavEventsResponse, GetIntegrationsCaldavEventsResponses, GetIntegrationsConsumerDataData, GetIntegrationsConsumerDataResponse, GetIntegrationsConsumerDataResponses, GetIntegrationsData, GetIntegrationsResponse, GetIntegrationsResponses, GetIntegrationsWidgetPropertiesData, GetIntegrationsWidgetPropertiesResponse, GetIntegrationsWidgetPropertiesResponses, GetJobsPullIconsData, GetJobsPullIconsError, GetJobsPullIconsErrors, GetJobsPullIconsResponse, GetJobsPullIconsResponses, GetJobsSearchItemsData, GetJobsSearchItemsResponse, GetJobsSearchItemsResponses, GetLinksCollectionsData, GetLinksCollectionsResponse, GetLinksCollectionsResponses, GetLinksFoldersData, GetLinksFoldersResponse, GetLinksFoldersResponses, GetLinksHomeData, GetLinksHomeGroupsData, GetLinksHomeGroupsResponse, GetLinksHomeGroupsResponses, GetLinksHomeResponse, GetLinksHomeResponses, GetLinksItemsData, GetLinksItemsResponse, GetLinksItemsResponses, GetLinksTagsData, GetLinksTagsResponse, GetLinksTagsResponses, GetLocationsData, GetLocationsResponse, GetLocationsResponses, GetMonitoringHostsByIdData, GetMonitoringHostsByIdHistoryData, GetMonitoringHostsByIdHistoryResponse, GetMonitoringHostsByIdHistoryResponses, GetMonitoringHostsByIdResponse, GetMonitoringHostsByIdResponses, GetMonitoringHostsByIdStatsData, GetMonitoringHostsByIdStatsResponse, GetMonitoringHostsByIdStatsResponses, GetMonitoringHostsData, GetMonitoringHostsResponse, GetMonitoringHostsResponses, GetMonitoringSshHostsData, GetMonitoringSshHostsResponse, GetMonitoringSshHostsResponses, GetMonitoringStatusData, GetMonitoringStatusResponse, GetMonitoringStatusResponses, GetMonitorsByIdData, GetMonitorsByIdResponse, GetMonitorsByIdResponses, GetMonitorsData, GetMonitorsResponse, GetMonitorsResponses, GetNewsData, GetNewsFeedData, GetNewsFeedMetadataData, GetNewsFeedMetadataResponse, GetNewsFeedMetadataResponses, GetNewsFeedRecordsByIdData, GetNewsFeedRecordsByIdResponse, GetNewsFeedRecordsByIdResponses, GetNewsFeedRefreshData, GetNewsFeedRefreshResponse, GetNewsFeedRefreshResponses, GetNewsFeedResponse, GetNewsFeedResponses, GetNewsFeedsByIdData, GetNewsFeedsByIdResponse, GetNewsFeedsByIdResponses, GetNewsFeedsData, GetNewsFeedsResponse, GetNewsFeedsResponses, GetNewsResponse, GetNewsResponses, GetNewsSubscriptionsByIdJsonData, GetNewsSubscriptionsByIdJsonResponse, GetNewsSubscriptionsByIdJsonResponses, GetNewsSubscriptionsData, GetNewsSubscriptionsResponse, GetNewsSubscriptionsResponses, GetNotificationsData, GetNotificationsForwardersData, GetNotificationsForwardersResponse, GetNotificationsForwardersResponses, GetNotificationsResponse, GetNotificationsResponses, GetNotificationsTopicsData, GetNotificationsTopicsResponse, GetNotificationsTopicsResponses, GetNotificationsTopicTokensData, GetNotificationsTopicTokensResponse, GetNotificationsTopicTokensResponses, GetPageConfigData, GetPageConfigResponse, GetPageConfigResponses, GetPageConfigUserPagesData, GetPageConfigUserPagesResponse, GetPageConfigUserPagesResponses, GetSearchItemsData, GetSearchItemsFrequentlyUsedData, GetSearchItemsFrequentlyUsedResponse, GetSearchItemsFrequentlyUsedResponses, GetSearchItemsResponse, GetSearchItemsResponses, GetTestBookmarksData, GetTestBookmarksResponse, GetTestBookmarksResponses, GetWallpapersData, GetWallpapersResponse, GetWallpapersResponses, GetWeatherData, GetWeatherResponse, GetWeatherResponses, GetWidgetsByIntegrationData, GetWidgetsByIntegrationResponse, GetWidgetsByIntegrationResponses, GetWidgetsData, GetWidgetsGlanceableData, GetWidgetsGlanceableResponse, GetWidgetsGlanceableResponses, GetWidgetsGlanceablesData, GetWidgetsGlanceablesResponse, GetWidgetsGlanceablesResponses, GetWidgetsResponse, GetWidgetsResponses, Id, JsonBody, PatchAuthUpdateUserPropertyData, PatchAuthUpdateUserPropertyError, PatchAuthUpdateUserPropertyErrors, PatchAuthUpdateUserPropertyResponse, PatchAuthUpdateUserPropertyResponses, PostAuthChangePasswordData, PostAuthChangePasswordError, PostAuthChangePasswordErrors, PostAuthChangePasswordResponse, PostAuthChangePasswordResponses, PostAuthLoginData, PostAuthLoginError, PostAuthLoginErrors, PostAuthLoginResponse, PostAuthLoginResponses, PostAuthMfaData, PostAuthMfaError, PostAuthMfaErrors, PostAuthMfaResponse, PostAuthMfaResponses, PostAuthSignupData, PostAuthSignupError, PostAuthSignupErrors, PostAuthSignupResponse, PostAuthSignupResponses, PostAuthValidateAuthData, PostAuthValidateAuthError, PostAuthValidateAuthErrors, PostAuthValidateAuthResponse, PostAuthValidateAuthResponses, PostIntegrationsConsumerDataData, PostIntegrationsConsumerDataResponse, PostIntegrationsConsumerDataResponses, PostIntegrationsData, PostIntegrationsProxyActionData, PostIntegrationsProxyActionResponse, PostIntegrationsProxyActionResponses, PostIntegrationsResponse, PostIntegrationsResponses, PostIntegrationsTestEndpointData, PostIntegrationsTestEndpointResponse, PostIntegrationsTestEndpointResponses, PostLinksCollectionsData, PostLinksCollectionsResponse, PostLinksCollectionsResponses, PostLinksFoldersData, PostLinksFoldersResponse, PostLinksFoldersResponses, PostLinksHomeGroupsData, PostLinksHomeGroupsResponse, PostLinksHomeGroupsResponses, PostLinksItemsData, PostLinksItemsResponse, PostLinksItemsResponses, PostLinksReorderData, PostLinksReorderResponse, PostLinksReorderResponses, PostLinksTagsData, PostLinksTagsResponse, PostLinksTagsResponses, PostMonitoringHostsByIdRefreshData, PostMonitoringHostsByIdRefreshError, PostMonitoringHostsByIdRefreshErrors, PostMonitoringHostsByIdRefreshResponse, PostMonitoringHostsByIdRefreshResponses, PostMonitoringHostsData, PostMonitoringHostsResponse, PostMonitoringHostsResponses, PostMonitoringSshHostsData, PostMonitoringSshHostsResponse, PostMonitoringSshHostsResponses, PostMonitoringStatusData, PostMonitoringStatusError, PostMonitoringStatusErrors, PostMonitoringStatusResponse, PostMonitoringStatusResponses, PostMonitorsData, PostMonitorsResponse, PostMonitorsResponses, PostNewsFeedRecordsByIdData, PostNewsFeedRecordsByIdResponse, PostNewsFeedRecordsByIdResponses, PostNewsFeedRecordsData, PostNewsFeedRecordsResponse, PostNewsFeedRecordsResponses, PostNewsFeedRefreshData, PostNewsFeedRefreshResponse, PostNewsFeedRefreshResponses, PostNewsFeedSubscribeData, PostNewsFeedSubscribeResponse, PostNewsFeedSubscribeResponses, PostNewsFeedUnsubscribeData, PostNewsFeedUnsubscribeResponse, PostNewsFeedUnsubscribeResponses, PostNewsFeedUpdateData, PostNewsFeedUpdateResponse, PostNewsFeedUpdateResponses, PostNewsFixMissingTitlesData, PostNewsFixMissingTitlesResponse, PostNewsFixMissingTitlesResponses, PostNotificationsByTopicData, PostNotificationsByTopicResponse, PostNotificationsByTopicResponses, PostNotificationsData, PostNotificationsForwardersData, PostNotificationsForwardersResponse, PostNotificationsForwardersResponses, PostNotificationsForwardersTestData, PostNotificationsForwardersTestResponse, PostNotificationsForwardersTestResponses, PostNotificationsMarkAsReadData, PostNotificationsMarkAsReadResponse, PostNotificationsMarkAsReadResponses, PostNotificationsResponse, PostNotificationsResponses, PostNotificationsTestData, PostNotificationsTestResponse, PostNotificationsTestResponses, PostNotificationsTopicsData, PostNotificationsTopicsResponse, PostNotificationsTopicsResponses, PostNotificationsTopicTokensData, PostNotificationsTopicTokensResponse, PostNotificationsTopicTokensResponses, PostPageConfigHomeData, PostPageConfigHomeResponse, PostPageConfigHomeResponses, PostPageConfigIntegrationDataData, PostPageConfigIntegrationDataResponse, PostPageConfigIntegrationDataResponses, PostPageConfigMigrateLegacyData, PostPageConfigMigrateLegacyResponse, PostPageConfigMigrateLegacyResponses, PostSearchItemsUsageStatsData, PostSearchItemsUsageStatsResponse, PostSearchItemsUsageStatsResponses, PostWallpapersData, PostWallpapersResponse, PostWallpapersResponses, PutIntegrationsByIdData, PutIntegrationsByIdResponse, PutIntegrationsByIdResponses, PutLinksCollectionsByCollectionIdData, PutLinksCollectionsByCollectionIdResponse, PutLinksCollectionsByCollectionIdResponses, PutLinksFoldersByFolderIdIconData, PutLinksFoldersByFolderIdIconResponse, PutLinksFoldersByFolderIdIconResponses, PutLinksItemsByLinkIdData, PutLinksItemsByLinkIdResponse, PutLinksItemsByLinkIdResponses, PutLinksTagsByTagIdData, PutLinksTagsByTagIdResponse, PutLinksTagsByTagIdResponses, PutMonitoringHostsByIdData, PutMonitoringHostsByIdResponse, PutMonitoringHostsByIdResponses, PutMonitoringSshHostsByIdData, PutMonitoringSshHostsByIdResponse, PutMonitoringSshHostsByIdResponses, PutMonitorsByIdData, PutMonitorsByIdResponse, PutMonitorsByIdResponses, PutNotificationsForwardersData, PutNotificationsForwardersResponse, PutNotificationsForwardersResponses, PutNotificationsTopicTokensData, PutNotificationsTopicTokensResponse, PutNotificationsTopicTokensResponses, PutPageConfigData, PutPageConfigResponse, PutPageConfigResponses } from './types.gen'; +export { deleteAuthDeleteAccount, deleteIntegrationsById, deleteLinksItemsByLinkId, deleteMonitoringHostsById, deleteMonitoringSshHostsById, deleteMonitorsById, deleteNewsFeedRecordsById, deleteNotificationsForwarders, deleteNotificationsTopics, deleteNotificationsTopicTokens, getAppConfig, getAppInfo, getAuthCallback, getAuthSso, getGlanceables, getGlanceablesByIntegration, getIntegrations, getIntegrationsCaldavEvents, getIntegrationsConsumerData, getIntegrationsWidgetProperties, getJobsPullIcons, getJobsSearchItems, getLinksCollections, getLinksFolders, getLinksHome, getLinksHomeGroups, getLinksItems, getLinksTags, getLocations, getMonitoringHosts, getMonitoringHostsById, getMonitoringHostsByIdHistory, getMonitoringHostsByIdStats, getMonitoringSshHosts, getMonitoringStatus, getMonitors, getMonitorsById, getNews, getNewsFeed, getNewsFeedMetadata, getNewsFeedRecordsById, getNewsFeedRefresh, getNewsFeeds, getNewsFeedsById, getNewsSubscriptions, getNewsSubscriptionsByIdJson, getNotifications, getNotificationsForwarders, getNotificationsTopics, getNotificationsTopicTokens, getPageConfig, getPageConfigUserPages, getSearchItems, getSearchItemsFrequentlyUsed, getSessionsCurrent, getTestBookmarks, getWallpapers, getWeather, getWidgets, getWidgetsByIntegration, getWidgetsGlanceable, getWidgetsGlanceables, type Options, patchAuthUpdateUserProperty, patchSessionsCurrent, postAuthChangePassword, postAuthLogin, postAuthMfa, postAuthSignup, postAuthValidateAuth, postIntegrations, postIntegrationsConsumerData, postIntegrationsProxyAction, postIntegrationsTestEndpoint, postLinksCollections, postLinksFolders, postLinksHomeGroups, postLinksItems, postLinksReorder, postLinksTags, postMonitoringHosts, postMonitoringHostsByIdRefresh, postMonitoringSshHosts, postMonitoringStatus, postMonitors, postNewsFeedRecords, postNewsFeedRecordsById, postNewsFeedRefresh, postNewsFeedSubscribe, postNewsFeedUnsubscribe, postNewsFeedUpdate, postNewsFixMissingTitles, postNotifications, postNotificationsByTopic, postNotificationsForwarders, postNotificationsForwardersTest, postNotificationsMarkAsRead, postNotificationsTest, postNotificationsTopics, postNotificationsTopicTokens, postPageConfigHome, postPageConfigIntegrationData, postPageConfigMigrateLegacy, postSearchItemsUsageStats, postWallpapers, putIntegrationsById, putLinksCollectionsByCollectionId, putLinksFoldersByFolderIdIcon, putLinksItemsByLinkId, putLinksTagsByTagId, putMonitoringHostsById, putMonitoringSshHostsById, putMonitorsById, putNotificationsForwarders, putNotificationsTopicTokens, putPageConfig } from './sdk.gen'; +export type { ClientOptions, DeleteAuthDeleteAccountData, DeleteAuthDeleteAccountError, DeleteAuthDeleteAccountErrors, DeleteAuthDeleteAccountResponse, DeleteAuthDeleteAccountResponses, DeleteIntegrationsByIdData, DeleteIntegrationsByIdResponse, DeleteIntegrationsByIdResponses, DeleteLinksItemsByLinkIdData, DeleteLinksItemsByLinkIdResponse, DeleteLinksItemsByLinkIdResponses, DeleteMonitoringHostsByIdData, DeleteMonitoringHostsByIdResponse, DeleteMonitoringHostsByIdResponses, DeleteMonitoringSshHostsByIdData, DeleteMonitoringSshHostsByIdResponse, DeleteMonitoringSshHostsByIdResponses, DeleteMonitorsByIdData, DeleteMonitorsByIdResponse, DeleteMonitorsByIdResponses, DeleteNewsFeedRecordsByIdData, DeleteNewsFeedRecordsByIdResponse, DeleteNewsFeedRecordsByIdResponses, DeleteNotificationsForwardersData, DeleteNotificationsForwardersResponse, DeleteNotificationsForwardersResponses, DeleteNotificationsTopicsData, DeleteNotificationsTopicsResponse, DeleteNotificationsTopicsResponses, DeleteNotificationsTopicTokensData, DeleteNotificationsTopicTokensResponse, DeleteNotificationsTopicTokensResponses, Error, GenericObject, GetAppConfigData, GetAppConfigResponse, GetAppConfigResponses, GetAppInfoData, GetAppInfoResponse, GetAppInfoResponses, GetAuthCallbackData, GetAuthCallbackResponse, GetAuthCallbackResponses, GetAuthSsoData, GetAuthSsoResponse, GetAuthSsoResponses, GetGlanceablesByIntegrationData, GetGlanceablesByIntegrationResponse, GetGlanceablesByIntegrationResponses, GetGlanceablesData, GetGlanceablesResponse, GetGlanceablesResponses, GetIntegrationsCaldavEventsData, GetIntegrationsCaldavEventsResponse, GetIntegrationsCaldavEventsResponses, GetIntegrationsConsumerDataData, GetIntegrationsConsumerDataResponse, GetIntegrationsConsumerDataResponses, GetIntegrationsData, GetIntegrationsResponse, GetIntegrationsResponses, GetIntegrationsWidgetPropertiesData, GetIntegrationsWidgetPropertiesResponse, GetIntegrationsWidgetPropertiesResponses, GetJobsPullIconsData, GetJobsPullIconsError, GetJobsPullIconsErrors, GetJobsPullIconsResponse, GetJobsPullIconsResponses, GetJobsSearchItemsData, GetJobsSearchItemsResponse, GetJobsSearchItemsResponses, GetLinksCollectionsData, GetLinksCollectionsResponse, GetLinksCollectionsResponses, GetLinksFoldersData, GetLinksFoldersResponse, GetLinksFoldersResponses, GetLinksHomeData, GetLinksHomeGroupsData, GetLinksHomeGroupsResponse, GetLinksHomeGroupsResponses, GetLinksHomeResponse, GetLinksHomeResponses, GetLinksItemsData, GetLinksItemsResponse, GetLinksItemsResponses, GetLinksTagsData, GetLinksTagsResponse, GetLinksTagsResponses, GetLocationsData, GetLocationsResponse, GetLocationsResponses, GetMonitoringHostsByIdData, GetMonitoringHostsByIdHistoryData, GetMonitoringHostsByIdHistoryResponse, GetMonitoringHostsByIdHistoryResponses, GetMonitoringHostsByIdResponse, GetMonitoringHostsByIdResponses, GetMonitoringHostsByIdStatsData, GetMonitoringHostsByIdStatsResponse, GetMonitoringHostsByIdStatsResponses, GetMonitoringHostsData, GetMonitoringHostsResponse, GetMonitoringHostsResponses, GetMonitoringSshHostsData, GetMonitoringSshHostsResponse, GetMonitoringSshHostsResponses, GetMonitoringStatusData, GetMonitoringStatusResponse, GetMonitoringStatusResponses, GetMonitorsByIdData, GetMonitorsByIdResponse, GetMonitorsByIdResponses, GetMonitorsData, GetMonitorsResponse, GetMonitorsResponses, GetNewsData, GetNewsFeedData, GetNewsFeedMetadataData, GetNewsFeedMetadataResponse, GetNewsFeedMetadataResponses, GetNewsFeedRecordsByIdData, GetNewsFeedRecordsByIdResponse, GetNewsFeedRecordsByIdResponses, GetNewsFeedRefreshData, GetNewsFeedRefreshResponse, GetNewsFeedRefreshResponses, GetNewsFeedResponse, GetNewsFeedResponses, GetNewsFeedsByIdData, GetNewsFeedsByIdResponse, GetNewsFeedsByIdResponses, GetNewsFeedsData, GetNewsFeedsResponse, GetNewsFeedsResponses, GetNewsResponse, GetNewsResponses, GetNewsSubscriptionsByIdJsonData, GetNewsSubscriptionsByIdJsonResponse, GetNewsSubscriptionsByIdJsonResponses, GetNewsSubscriptionsData, GetNewsSubscriptionsResponse, GetNewsSubscriptionsResponses, GetNotificationsData, GetNotificationsForwardersData, GetNotificationsForwardersResponse, GetNotificationsForwardersResponses, GetNotificationsResponse, GetNotificationsResponses, GetNotificationsTopicsData, GetNotificationsTopicsResponse, GetNotificationsTopicsResponses, GetNotificationsTopicTokensData, GetNotificationsTopicTokensResponse, GetNotificationsTopicTokensResponses, GetPageConfigData, GetPageConfigResponse, GetPageConfigResponses, GetPageConfigUserPagesData, GetPageConfigUserPagesResponse, GetPageConfigUserPagesResponses, GetSearchItemsData, GetSearchItemsFrequentlyUsedData, GetSearchItemsFrequentlyUsedResponse, GetSearchItemsFrequentlyUsedResponses, GetSearchItemsResponse, GetSearchItemsResponses, GetSessionsCurrentData, GetSessionsCurrentError, GetSessionsCurrentErrors, GetSessionsCurrentResponse, GetSessionsCurrentResponses, GetTestBookmarksData, GetTestBookmarksResponse, GetTestBookmarksResponses, GetWallpapersData, GetWallpapersResponse, GetWallpapersResponses, GetWeatherData, GetWeatherResponse, GetWeatherResponses, GetWidgetsByIntegrationData, GetWidgetsByIntegrationResponse, GetWidgetsByIntegrationResponses, GetWidgetsData, GetWidgetsGlanceableData, GetWidgetsGlanceableResponse, GetWidgetsGlanceableResponses, GetWidgetsGlanceablesData, GetWidgetsGlanceablesResponse, GetWidgetsGlanceablesResponses, GetWidgetsResponse, GetWidgetsResponses, Id, JsonBody, PatchAuthUpdateUserPropertyData, PatchAuthUpdateUserPropertyError, PatchAuthUpdateUserPropertyErrors, PatchAuthUpdateUserPropertyResponse, PatchAuthUpdateUserPropertyResponses, PatchSessionsCurrentData, PatchSessionsCurrentError, PatchSessionsCurrentErrors, PatchSessionsCurrentResponse, PatchSessionsCurrentResponses, PostAuthChangePasswordData, PostAuthChangePasswordError, PostAuthChangePasswordErrors, PostAuthChangePasswordResponse, PostAuthChangePasswordResponses, PostAuthLoginData, PostAuthLoginError, PostAuthLoginErrors, PostAuthLoginResponse, PostAuthLoginResponses, PostAuthMfaData, PostAuthMfaError, PostAuthMfaErrors, PostAuthMfaResponse, PostAuthMfaResponses, PostAuthSignupData, PostAuthSignupError, PostAuthSignupErrors, PostAuthSignupResponse, PostAuthSignupResponses, PostAuthValidateAuthData, PostAuthValidateAuthError, PostAuthValidateAuthErrors, PostAuthValidateAuthResponse, PostAuthValidateAuthResponses, PostIntegrationsConsumerDataData, PostIntegrationsConsumerDataResponse, PostIntegrationsConsumerDataResponses, PostIntegrationsData, PostIntegrationsProxyActionData, PostIntegrationsProxyActionResponse, PostIntegrationsProxyActionResponses, PostIntegrationsResponse, PostIntegrationsResponses, PostIntegrationsTestEndpointData, PostIntegrationsTestEndpointResponse, PostIntegrationsTestEndpointResponses, PostLinksCollectionsData, PostLinksCollectionsResponse, PostLinksCollectionsResponses, PostLinksFoldersData, PostLinksFoldersResponse, PostLinksFoldersResponses, PostLinksHomeGroupsData, PostLinksHomeGroupsResponse, PostLinksHomeGroupsResponses, PostLinksItemsData, PostLinksItemsResponse, PostLinksItemsResponses, PostLinksReorderData, PostLinksReorderResponse, PostLinksReorderResponses, PostLinksTagsData, PostLinksTagsResponse, PostLinksTagsResponses, PostMonitoringHostsByIdRefreshData, PostMonitoringHostsByIdRefreshError, PostMonitoringHostsByIdRefreshErrors, PostMonitoringHostsByIdRefreshResponse, PostMonitoringHostsByIdRefreshResponses, PostMonitoringHostsData, PostMonitoringHostsResponse, PostMonitoringHostsResponses, PostMonitoringSshHostsData, PostMonitoringSshHostsResponse, PostMonitoringSshHostsResponses, PostMonitoringStatusData, PostMonitoringStatusError, PostMonitoringStatusErrors, PostMonitoringStatusResponse, PostMonitoringStatusResponses, PostMonitorsData, PostMonitorsResponse, PostMonitorsResponses, PostNewsFeedRecordsByIdData, PostNewsFeedRecordsByIdResponse, PostNewsFeedRecordsByIdResponses, PostNewsFeedRecordsData, PostNewsFeedRecordsResponse, PostNewsFeedRecordsResponses, PostNewsFeedRefreshData, PostNewsFeedRefreshResponse, PostNewsFeedRefreshResponses, PostNewsFeedSubscribeData, PostNewsFeedSubscribeResponse, PostNewsFeedSubscribeResponses, PostNewsFeedUnsubscribeData, PostNewsFeedUnsubscribeResponse, PostNewsFeedUnsubscribeResponses, PostNewsFeedUpdateData, PostNewsFeedUpdateResponse, PostNewsFeedUpdateResponses, PostNewsFixMissingTitlesData, PostNewsFixMissingTitlesResponse, PostNewsFixMissingTitlesResponses, PostNotificationsByTopicData, PostNotificationsByTopicResponse, PostNotificationsByTopicResponses, PostNotificationsData, PostNotificationsForwardersData, PostNotificationsForwardersResponse, PostNotificationsForwardersResponses, PostNotificationsForwardersTestData, PostNotificationsForwardersTestResponse, PostNotificationsForwardersTestResponses, PostNotificationsMarkAsReadData, PostNotificationsMarkAsReadResponse, PostNotificationsMarkAsReadResponses, PostNotificationsResponse, PostNotificationsResponses, PostNotificationsTestData, PostNotificationsTestResponse, PostNotificationsTestResponses, PostNotificationsTopicsData, PostNotificationsTopicsResponse, PostNotificationsTopicsResponses, PostNotificationsTopicTokensData, PostNotificationsTopicTokensResponse, PostNotificationsTopicTokensResponses, PostPageConfigHomeData, PostPageConfigHomeResponse, PostPageConfigHomeResponses, PostPageConfigIntegrationDataData, PostPageConfigIntegrationDataResponse, PostPageConfigIntegrationDataResponses, PostPageConfigMigrateLegacyData, PostPageConfigMigrateLegacyResponse, PostPageConfigMigrateLegacyResponses, PostSearchItemsUsageStatsData, PostSearchItemsUsageStatsResponse, PostSearchItemsUsageStatsResponses, PostWallpapersData, PostWallpapersResponse, PostWallpapersResponses, PutIntegrationsByIdData, PutIntegrationsByIdResponse, PutIntegrationsByIdResponses, PutLinksCollectionsByCollectionIdData, PutLinksCollectionsByCollectionIdResponse, PutLinksCollectionsByCollectionIdResponses, PutLinksFoldersByFolderIdIconData, PutLinksFoldersByFolderIdIconResponse, PutLinksFoldersByFolderIdIconResponses, PutLinksItemsByLinkIdData, PutLinksItemsByLinkIdResponse, PutLinksItemsByLinkIdResponses, PutLinksTagsByTagIdData, PutLinksTagsByTagIdResponse, PutLinksTagsByTagIdResponses, PutMonitoringHostsByIdData, PutMonitoringHostsByIdResponse, PutMonitoringHostsByIdResponses, PutMonitoringSshHostsByIdData, PutMonitoringSshHostsByIdResponse, PutMonitoringSshHostsByIdResponses, PutMonitorsByIdData, PutMonitorsByIdResponse, PutMonitorsByIdResponses, PutNotificationsForwardersData, PutNotificationsForwardersResponse, PutNotificationsForwardersResponses, PutNotificationsTopicTokensData, PutNotificationsTopicTokensResponse, PutNotificationsTopicTokensResponses, PutPageConfigData, PutPageConfigResponse, PutPageConfigResponses } from './types.gen'; diff --git a/apps/web/src/lib/api/sdk.gen.ts b/apps/web/src/lib/api/sdk.gen.ts index 38c68db3..113897a2 100644 --- a/apps/web/src/lib/api/sdk.gen.ts +++ b/apps/web/src/lib/api/sdk.gen.ts @@ -3,7 +3,7 @@ import type { Client, ClientMeta, Options as Options2, RequestResult, TDataShape } from './client'; import { client } from './client.gen'; -import type { DeleteAuthDeleteAccountData, DeleteAuthDeleteAccountErrors, DeleteAuthDeleteAccountResponses, DeleteIntegrationsByIdData, DeleteIntegrationsByIdResponses, DeleteLinksItemsByLinkIdData, DeleteLinksItemsByLinkIdResponses, DeleteMonitoringHostsByIdData, DeleteMonitoringHostsByIdResponses, DeleteMonitoringSshHostsByIdData, DeleteMonitoringSshHostsByIdResponses, DeleteMonitorsByIdData, DeleteMonitorsByIdResponses, DeleteNewsFeedRecordsByIdData, DeleteNewsFeedRecordsByIdResponses, DeleteNotificationsForwardersData, DeleteNotificationsForwardersResponses, DeleteNotificationsTopicsData, DeleteNotificationsTopicsResponses, DeleteNotificationsTopicTokensData, DeleteNotificationsTopicTokensResponses, GetAppConfigData, GetAppConfigResponses, GetAppInfoData, GetAppInfoResponses, GetAuthCallbackData, GetAuthCallbackResponses, GetAuthSsoData, GetAuthSsoResponses, GetGlanceablesByIntegrationData, GetGlanceablesByIntegrationResponses, GetGlanceablesData, GetGlanceablesResponses, GetIntegrationsCaldavEventsData, GetIntegrationsCaldavEventsResponses, GetIntegrationsConsumerDataData, GetIntegrationsConsumerDataResponses, GetIntegrationsData, GetIntegrationsResponses, GetIntegrationsWidgetPropertiesData, GetIntegrationsWidgetPropertiesResponses, GetJobsPullIconsData, GetJobsPullIconsErrors, GetJobsPullIconsResponses, GetJobsSearchItemsData, GetJobsSearchItemsResponses, GetLinksCollectionsData, GetLinksCollectionsResponses, GetLinksFoldersData, GetLinksFoldersResponses, GetLinksHomeData, GetLinksHomeGroupsData, GetLinksHomeGroupsResponses, GetLinksHomeResponses, GetLinksItemsData, GetLinksItemsResponses, GetLinksTagsData, GetLinksTagsResponses, GetLocationsData, GetLocationsResponses, GetMonitoringHostsByIdData, GetMonitoringHostsByIdHistoryData, GetMonitoringHostsByIdHistoryResponses, GetMonitoringHostsByIdResponses, GetMonitoringHostsByIdStatsData, GetMonitoringHostsByIdStatsResponses, GetMonitoringHostsData, GetMonitoringHostsResponses, GetMonitoringSshHostsData, GetMonitoringSshHostsResponses, GetMonitoringStatusData, GetMonitoringStatusResponses, GetMonitorsByIdData, GetMonitorsByIdResponses, GetMonitorsData, GetMonitorsResponses, GetNewsData, GetNewsFeedData, GetNewsFeedMetadataData, GetNewsFeedMetadataResponses, GetNewsFeedRecordsByIdData, GetNewsFeedRecordsByIdResponses, GetNewsFeedRefreshData, GetNewsFeedRefreshResponses, GetNewsFeedResponses, GetNewsFeedsByIdData, GetNewsFeedsByIdResponses, GetNewsFeedsData, GetNewsFeedsResponses, GetNewsResponses, GetNewsSubscriptionsByIdJsonData, GetNewsSubscriptionsByIdJsonResponses, GetNewsSubscriptionsData, GetNewsSubscriptionsResponses, GetNotificationsData, GetNotificationsForwardersData, GetNotificationsForwardersResponses, GetNotificationsResponses, GetNotificationsTopicsData, GetNotificationsTopicsResponses, GetNotificationsTopicTokensData, GetNotificationsTopicTokensResponses, GetPageConfigData, GetPageConfigResponses, GetPageConfigUserPagesData, GetPageConfigUserPagesResponses, GetSearchItemsData, GetSearchItemsFrequentlyUsedData, GetSearchItemsFrequentlyUsedResponses, GetSearchItemsResponses, GetTestBookmarksData, GetTestBookmarksResponses, GetWallpapersData, GetWallpapersResponses, GetWeatherData, GetWeatherResponses, GetWidgetsByIntegrationData, GetWidgetsByIntegrationResponses, GetWidgetsData, GetWidgetsGlanceableData, GetWidgetsGlanceableResponses, GetWidgetsGlanceablesData, GetWidgetsGlanceablesResponses, GetWidgetsResponses, PatchAuthUpdateUserPropertyData, PatchAuthUpdateUserPropertyErrors, PatchAuthUpdateUserPropertyResponses, PostAuthChangePasswordData, PostAuthChangePasswordErrors, PostAuthChangePasswordResponses, PostAuthLoginData, PostAuthLoginErrors, PostAuthLoginResponses, PostAuthMfaData, PostAuthMfaErrors, PostAuthMfaResponses, PostAuthSignupData, PostAuthSignupErrors, PostAuthSignupResponses, PostAuthValidateAuthData, PostAuthValidateAuthErrors, PostAuthValidateAuthResponses, PostIntegrationsConsumerDataData, PostIntegrationsConsumerDataResponses, PostIntegrationsData, PostIntegrationsProxyActionData, PostIntegrationsProxyActionResponses, PostIntegrationsResponses, PostIntegrationsTestEndpointData, PostIntegrationsTestEndpointResponses, PostLinksCollectionsData, PostLinksCollectionsResponses, PostLinksFoldersData, PostLinksFoldersResponses, PostLinksHomeGroupsData, PostLinksHomeGroupsResponses, PostLinksItemsData, PostLinksItemsResponses, PostLinksReorderData, PostLinksReorderResponses, PostLinksTagsData, PostLinksTagsResponses, PostMonitoringHostsByIdRefreshData, PostMonitoringHostsByIdRefreshErrors, PostMonitoringHostsByIdRefreshResponses, PostMonitoringHostsData, PostMonitoringHostsResponses, PostMonitoringSshHostsData, PostMonitoringSshHostsResponses, PostMonitoringStatusData, PostMonitoringStatusErrors, PostMonitoringStatusResponses, PostMonitorsData, PostMonitorsResponses, PostNewsFeedRecordsByIdData, PostNewsFeedRecordsByIdResponses, PostNewsFeedRecordsData, PostNewsFeedRecordsResponses, PostNewsFeedRefreshData, PostNewsFeedRefreshResponses, PostNewsFeedSubscribeData, PostNewsFeedSubscribeResponses, PostNewsFeedUnsubscribeData, PostNewsFeedUnsubscribeResponses, PostNewsFeedUpdateData, PostNewsFeedUpdateResponses, PostNewsFixMissingTitlesData, PostNewsFixMissingTitlesResponses, PostNotificationsByTopicData, PostNotificationsByTopicResponses, PostNotificationsData, PostNotificationsForwardersData, PostNotificationsForwardersResponses, PostNotificationsForwardersTestData, PostNotificationsForwardersTestResponses, PostNotificationsMarkAsReadData, PostNotificationsMarkAsReadResponses, PostNotificationsResponses, PostNotificationsTestData, PostNotificationsTestResponses, PostNotificationsTopicsData, PostNotificationsTopicsResponses, PostNotificationsTopicTokensData, PostNotificationsTopicTokensResponses, PostPageConfigHomeData, PostPageConfigHomeResponses, PostPageConfigIntegrationDataData, PostPageConfigIntegrationDataResponses, PostPageConfigMigrateLegacyData, PostPageConfigMigrateLegacyResponses, PostSearchItemsUsageStatsData, PostSearchItemsUsageStatsResponses, PostWallpapersData, PostWallpapersResponses, PutIntegrationsByIdData, PutIntegrationsByIdResponses, PutLinksCollectionsByCollectionIdData, PutLinksCollectionsByCollectionIdResponses, PutLinksFoldersByFolderIdIconData, PutLinksFoldersByFolderIdIconResponses, PutLinksItemsByLinkIdData, PutLinksItemsByLinkIdResponses, PutLinksTagsByTagIdData, PutLinksTagsByTagIdResponses, PutMonitoringHostsByIdData, PutMonitoringHostsByIdResponses, PutMonitoringSshHostsByIdData, PutMonitoringSshHostsByIdResponses, PutMonitorsByIdData, PutMonitorsByIdResponses, PutNotificationsForwardersData, PutNotificationsForwardersResponses, PutNotificationsTopicTokensData, PutNotificationsTopicTokensResponses, PutPageConfigData, PutPageConfigResponses } from './types.gen'; +import type { DeleteAuthDeleteAccountData, DeleteAuthDeleteAccountErrors, DeleteAuthDeleteAccountResponses, DeleteIntegrationsByIdData, DeleteIntegrationsByIdResponses, DeleteLinksItemsByLinkIdData, DeleteLinksItemsByLinkIdResponses, DeleteMonitoringHostsByIdData, DeleteMonitoringHostsByIdResponses, DeleteMonitoringSshHostsByIdData, DeleteMonitoringSshHostsByIdResponses, DeleteMonitorsByIdData, DeleteMonitorsByIdResponses, DeleteNewsFeedRecordsByIdData, DeleteNewsFeedRecordsByIdResponses, DeleteNotificationsForwardersData, DeleteNotificationsForwardersResponses, DeleteNotificationsTopicsData, DeleteNotificationsTopicsResponses, DeleteNotificationsTopicTokensData, DeleteNotificationsTopicTokensResponses, GetAppConfigData, GetAppConfigResponses, GetAppInfoData, GetAppInfoResponses, GetAuthCallbackData, GetAuthCallbackResponses, GetAuthSsoData, GetAuthSsoResponses, GetGlanceablesByIntegrationData, GetGlanceablesByIntegrationResponses, GetGlanceablesData, GetGlanceablesResponses, GetIntegrationsCaldavEventsData, GetIntegrationsCaldavEventsResponses, GetIntegrationsConsumerDataData, GetIntegrationsConsumerDataResponses, GetIntegrationsData, GetIntegrationsResponses, GetIntegrationsWidgetPropertiesData, GetIntegrationsWidgetPropertiesResponses, GetJobsPullIconsData, GetJobsPullIconsErrors, GetJobsPullIconsResponses, GetJobsSearchItemsData, GetJobsSearchItemsResponses, GetLinksCollectionsData, GetLinksCollectionsResponses, GetLinksFoldersData, GetLinksFoldersResponses, GetLinksHomeData, GetLinksHomeGroupsData, GetLinksHomeGroupsResponses, GetLinksHomeResponses, GetLinksItemsData, GetLinksItemsResponses, GetLinksTagsData, GetLinksTagsResponses, GetLocationsData, GetLocationsResponses, GetMonitoringHostsByIdData, GetMonitoringHostsByIdHistoryData, GetMonitoringHostsByIdHistoryResponses, GetMonitoringHostsByIdResponses, GetMonitoringHostsByIdStatsData, GetMonitoringHostsByIdStatsResponses, GetMonitoringHostsData, GetMonitoringHostsResponses, GetMonitoringSshHostsData, GetMonitoringSshHostsResponses, GetMonitoringStatusData, GetMonitoringStatusResponses, GetMonitorsByIdData, GetMonitorsByIdResponses, GetMonitorsData, GetMonitorsResponses, GetNewsData, GetNewsFeedData, GetNewsFeedMetadataData, GetNewsFeedMetadataResponses, GetNewsFeedRecordsByIdData, GetNewsFeedRecordsByIdResponses, GetNewsFeedRefreshData, GetNewsFeedRefreshResponses, GetNewsFeedResponses, GetNewsFeedsByIdData, GetNewsFeedsByIdResponses, GetNewsFeedsData, GetNewsFeedsResponses, GetNewsResponses, GetNewsSubscriptionsByIdJsonData, GetNewsSubscriptionsByIdJsonResponses, GetNewsSubscriptionsData, GetNewsSubscriptionsResponses, GetNotificationsData, GetNotificationsForwardersData, GetNotificationsForwardersResponses, GetNotificationsResponses, GetNotificationsTopicsData, GetNotificationsTopicsResponses, GetNotificationsTopicTokensData, GetNotificationsTopicTokensResponses, GetPageConfigData, GetPageConfigResponses, GetPageConfigUserPagesData, GetPageConfigUserPagesResponses, GetSearchItemsData, GetSearchItemsFrequentlyUsedData, GetSearchItemsFrequentlyUsedResponses, GetSearchItemsResponses, GetSessionsCurrentData, GetSessionsCurrentErrors, GetSessionsCurrentResponses, GetTestBookmarksData, GetTestBookmarksResponses, GetWallpapersData, GetWallpapersResponses, GetWeatherData, GetWeatherResponses, GetWidgetsByIntegrationData, GetWidgetsByIntegrationResponses, GetWidgetsData, GetWidgetsGlanceableData, GetWidgetsGlanceableResponses, GetWidgetsGlanceablesData, GetWidgetsGlanceablesResponses, GetWidgetsResponses, PatchAuthUpdateUserPropertyData, PatchAuthUpdateUserPropertyErrors, PatchAuthUpdateUserPropertyResponses, PatchSessionsCurrentData, PatchSessionsCurrentErrors, PatchSessionsCurrentResponses, PostAuthChangePasswordData, PostAuthChangePasswordErrors, PostAuthChangePasswordResponses, PostAuthLoginData, PostAuthLoginErrors, PostAuthLoginResponses, PostAuthMfaData, PostAuthMfaErrors, PostAuthMfaResponses, PostAuthSignupData, PostAuthSignupErrors, PostAuthSignupResponses, PostAuthValidateAuthData, PostAuthValidateAuthErrors, PostAuthValidateAuthResponses, PostIntegrationsConsumerDataData, PostIntegrationsConsumerDataResponses, PostIntegrationsData, PostIntegrationsProxyActionData, PostIntegrationsProxyActionResponses, PostIntegrationsResponses, PostIntegrationsTestEndpointData, PostIntegrationsTestEndpointResponses, PostLinksCollectionsData, PostLinksCollectionsResponses, PostLinksFoldersData, PostLinksFoldersResponses, PostLinksHomeGroupsData, PostLinksHomeGroupsResponses, PostLinksItemsData, PostLinksItemsResponses, PostLinksReorderData, PostLinksReorderResponses, PostLinksTagsData, PostLinksTagsResponses, PostMonitoringHostsByIdRefreshData, PostMonitoringHostsByIdRefreshErrors, PostMonitoringHostsByIdRefreshResponses, PostMonitoringHostsData, PostMonitoringHostsResponses, PostMonitoringSshHostsData, PostMonitoringSshHostsResponses, PostMonitoringStatusData, PostMonitoringStatusErrors, PostMonitoringStatusResponses, PostMonitorsData, PostMonitorsResponses, PostNewsFeedRecordsByIdData, PostNewsFeedRecordsByIdResponses, PostNewsFeedRecordsData, PostNewsFeedRecordsResponses, PostNewsFeedRefreshData, PostNewsFeedRefreshResponses, PostNewsFeedSubscribeData, PostNewsFeedSubscribeResponses, PostNewsFeedUnsubscribeData, PostNewsFeedUnsubscribeResponses, PostNewsFeedUpdateData, PostNewsFeedUpdateResponses, PostNewsFixMissingTitlesData, PostNewsFixMissingTitlesResponses, PostNotificationsByTopicData, PostNotificationsByTopicResponses, PostNotificationsData, PostNotificationsForwardersData, PostNotificationsForwardersResponses, PostNotificationsForwardersTestData, PostNotificationsForwardersTestResponses, PostNotificationsMarkAsReadData, PostNotificationsMarkAsReadResponses, PostNotificationsResponses, PostNotificationsTestData, PostNotificationsTestResponses, PostNotificationsTopicsData, PostNotificationsTopicsResponses, PostNotificationsTopicTokensData, PostNotificationsTopicTokensResponses, PostPageConfigHomeData, PostPageConfigHomeResponses, PostPageConfigIntegrationDataData, PostPageConfigIntegrationDataResponses, PostPageConfigMigrateLegacyData, PostPageConfigMigrateLegacyResponses, PostSearchItemsUsageStatsData, PostSearchItemsUsageStatsResponses, PostWallpapersData, PostWallpapersResponses, PutIntegrationsByIdData, PutIntegrationsByIdResponses, PutLinksCollectionsByCollectionIdData, PutLinksCollectionsByCollectionIdResponses, PutLinksFoldersByFolderIdIconData, PutLinksFoldersByFolderIdIconResponses, PutLinksItemsByLinkIdData, PutLinksItemsByLinkIdResponses, PutLinksTagsByTagIdData, PutLinksTagsByTagIdResponses, PutMonitoringHostsByIdData, PutMonitoringHostsByIdResponses, PutMonitoringSshHostsByIdData, PutMonitoringSshHostsByIdResponses, PutMonitorsByIdData, PutMonitorsByIdResponses, PutNotificationsForwardersData, PutNotificationsForwardersResponses, PutNotificationsTopicTokensData, PutNotificationsTopicTokensResponses, PutPageConfigData, PutPageConfigResponses } from './types.gen'; export type Options = Options2 & { /** @@ -123,6 +123,23 @@ export const patchAuthUpdateUserProperty = (options?: Options): RequestResult => (options?.client ?? client).get({ url: '/sessions/current', ...options }); + +/** + * Rename the current client session + */ +export const patchSessionsCurrent = (options?: Options): RequestResult => (options?.client ?? client).patch({ + url: '/sessions/current', + ...options, + headers: { + 'Content-Type': 'application/json', + ...options?.headers + } +}); + /** * List integrations */ diff --git a/apps/web/src/lib/api/types.gen.ts b/apps/web/src/lib/api/types.gen.ts index 6bb288a8..5c047ba0 100644 --- a/apps/web/src/lib/api/types.gen.ts +++ b/apps/web/src/lib/api/types.gen.ts @@ -262,6 +262,60 @@ export type PatchAuthUpdateUserPropertyResponses = { export type PatchAuthUpdateUserPropertyResponse = PatchAuthUpdateUserPropertyResponses[keyof PatchAuthUpdateUserPropertyResponses]; +export type GetSessionsCurrentData = { + body?: never; + path?: never; + query?: never; + url: '/sessions/current'; +}; + +export type GetSessionsCurrentErrors = { + /** + * Unauthorized + */ + 401: Error; +}; + +export type GetSessionsCurrentError = GetSessionsCurrentErrors[keyof GetSessionsCurrentErrors]; + +export type GetSessionsCurrentResponses = { + /** + * OK + */ + 200: GenericObject; +}; + +export type GetSessionsCurrentResponse = GetSessionsCurrentResponses[keyof GetSessionsCurrentResponses]; + +export type PatchSessionsCurrentData = { + body?: JsonBody; + path?: never; + query?: never; + url: '/sessions/current'; +}; + +export type PatchSessionsCurrentErrors = { + /** + * Bad Request + */ + 400: Error; + /** + * Unauthorized + */ + 401: Error; +}; + +export type PatchSessionsCurrentError = PatchSessionsCurrentErrors[keyof PatchSessionsCurrentErrors]; + +export type PatchSessionsCurrentResponses = { + /** + * OK + */ + 200: GenericObject; +}; + +export type PatchSessionsCurrentResponse = PatchSessionsCurrentResponses[keyof PatchSessionsCurrentResponses]; + export type GetIntegrationsData = { body?: never; path?: never; diff --git a/apps/web/src/lib/apiClient.ts b/apps/web/src/lib/apiClient.ts index 9d548f7e..48bbaf6c 100644 --- a/apps/web/src/lib/apiClient.ts +++ b/apps/web/src/lib/apiClient.ts @@ -16,6 +16,7 @@ import type { } from "@dashwise/types/sdk"; import type { PageConfig } from "@dashwise/types/sdk"; import config from "@/lib/config"; +import { getClientSessionHeaders } from "@/lib/session"; import { client } from "./api/client.gen"; import * as sdk from "./api/sdk.gen"; @@ -67,7 +68,11 @@ export function backendUrl(path: string) { } export function authHeaders(auth?: ActionAuth | null): Record | undefined { - return auth?.token ? { Authorization: `Bearer ${auth.token}` } : undefined; + if (!auth?.token) return undefined; + return { + Authorization: `Bearer ${auth.token}`, + ...getClientSessionHeaders(auth.sessionId), + }; } export type MonitoringSshHostRecord = { @@ -123,6 +128,18 @@ export type NewsFeedPageResponse = { limit: number; }; +export type SessionRecord = { + id: string; + user: string; + sessionId: string; + displayName: string; + clientType?: string; + platform?: string; + lastSeenAt: string; + created?: string; + updated?: string; +}; + function stringifyError(error: unknown) { if (typeof error === "string") return error; if (error && typeof error === "object") { @@ -152,7 +169,7 @@ export async function fetchWallpaperBlob(imageUrl: string, token?: string): Prom if (!isWallpaperApiUrl(url)) { const response = await fetch(url.toString(), { - headers: token ? { Authorization: `Bearer ${token}` } : undefined, + headers: token ? authHeaders({ token }) : undefined, }); handleUnauthorizedResponse(response); @@ -167,7 +184,7 @@ export async function fetchWallpaperBlob(imageUrl: string, token?: string): Prom const query = Object.fromEntries(url.searchParams.entries()); const result = await client.get({ url: "/wallpapers", - headers: token ? { Authorization: `Bearer ${token}` } : undefined, + headers: token ? authHeaders({ token }) : undefined, query, parseAs: "blob", }); @@ -227,7 +244,7 @@ export async function signupUserAction(payload: { _name?: string; email: string; } export async function validateAuthTokenAction(auth: ActionAuth): Promise { - return extractData(await postAuthValidateAuth({ body: auth })); + return extractData(await postAuthValidateAuth({ body: auth, headers: authHeaders(auth) })); } export async function deleteAccountAction(auth: ActionAuth, payload: { email: string; password: string; totp?: string }) { @@ -238,6 +255,23 @@ export async function updateUserPropertyAction(auth: ActionAuth, propertyName: s return extractData(await patchAuthUpdateUserProperty({ body: { auth, propertyName, propertyValue }, headers: authHeaders(auth) })) as Promise; } +// --- Session actions --- + +export async function getCurrentSessionAction(auth: ActionAuth): Promise { + return extractData(await client.get({ + url: "/sessions/current", + headers: authHeaders(auth), + })) as Promise; +} + +export async function renameCurrentSessionAction(auth: ActionAuth, displayName: string): Promise { + return extractData(await client.patch({ + url: "/sessions/current", + body: { displayName }, + headers: authHeaders(auth), + })) as Promise; +} + // --- Links actions --- export async function getLinksCollectionsAction(auth: ActionAuth) { diff --git a/apps/web/src/lib/queryClient.ts b/apps/web/src/lib/queryClient.ts index f5275f71..f40b0097 100644 --- a/apps/web/src/lib/queryClient.ts +++ b/apps/web/src/lib/queryClient.ts @@ -25,6 +25,7 @@ export const queryKeys = { appConfig: ["app-config"] as const, auth: { validation: (token: string | null) => ["auth", token, "validation"] as const, + session: (token: string | null) => ["auth", token, "session"] as const, }, links: { collections: ["links", "collections"] as const, diff --git a/apps/web/src/lib/rpcClient.ts b/apps/web/src/lib/rpcClient.ts index 6b6ee5b6..4edc8978 100644 --- a/apps/web/src/lib/rpcClient.ts +++ b/apps/web/src/lib/rpcClient.ts @@ -2,11 +2,14 @@ import { hc } from "hono/client"; import type { ActionAuth } from "@dashwise/types/sdk"; import { backendUrl } from "@/lib/apiClient"; +import { getClientSessionHeaders } from "@/lib/session"; const rpcClient = hc(backendUrl("/")); function authHeader(auth?: ActionAuth) { - return auth?.token ? { Authorization: `Bearer ${auth.token}` } : undefined; + return auth?.token + ? { Authorization: `Bearer ${auth.token}`, ...getClientSessionHeaders(auth.sessionId) } + : undefined; } async function parseRpcResponse(response: Response): Promise { @@ -56,6 +59,7 @@ export async function rpcUpdatePageConfig( config: Record, ) { const response = await rpcClient.rpc["page-config"].$put({ + header: authHeader(auth), json: { auth, pageName, config }, }); return parseRpcResponse(response); @@ -63,6 +67,7 @@ export async function rpcUpdatePageConfig( export async function rpcCreateHomePage(auth: ActionAuth) { const response = await rpcClient.rpc["page-config"].home.$post({ + header: authHeader(auth), json: { auth }, }); return parseRpcResponse(response); diff --git a/apps/web/src/lib/session.ts b/apps/web/src/lib/session.ts new file mode 100644 index 00000000..f0163bcd --- /dev/null +++ b/apps/web/src/lib/session.ts @@ -0,0 +1,36 @@ +const SESSION_ID_STORAGE_KEY = "dashwise_session_id"; + +function createFallbackSessionId() { + return `web-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 12)}`; +} + +/** Returns the browser identity that survives logout, login, and token refreshes. */ +export function getClientSessionId() { + if (typeof window === "undefined") return null; + + try { + const existing = window.localStorage.getItem(SESSION_ID_STORAGE_KEY)?.trim(); + if (existing) return existing; + + const sessionId = typeof window.crypto?.randomUUID === "function" + ? window.crypto.randomUUID() + : createFallbackSessionId(); + window.localStorage.setItem(SESSION_ID_STORAGE_KEY, sessionId); + return sessionId; + } catch { + return null; + } +} + +export function getClientSessionHeaders(preferredSessionId?: string | null) { + const sessionId = preferredSessionId?.trim() || getClientSessionId(); + if (!sessionId) return {}; + + return { + "X-Session-Id": sessionId, + "X-Client-Type": "browser", + ...(typeof navigator !== "undefined" && navigator.platform + ? { "X-Platform": navigator.platform.slice(0, 100) } + : {}), + }; +} diff --git a/packages/api-types/src/openapi.ts b/packages/api-types/src/openapi.ts index dd882855..8e74ec4e 100644 --- a/packages/api-types/src/openapi.ts +++ b/packages/api-types/src/openapi.ts @@ -356,6 +356,49 @@ export interface paths { }; trace?: never; }; + "/sessions/current": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** Get the current client session */ + get: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + 200: components["responses"]["JsonOk"]; + 401: components["responses"]["JsonUnauthorized"]; + }; + }; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + /** Rename the current client session */ + patch: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: components["requestBodies"]["JsonBody"]; + responses: { + 200: components["responses"]["JsonOk"]; + 400: components["responses"]["JsonBadRequest"]; + 401: components["responses"]["JsonUnauthorized"]; + }; + }; + trace?: never; + }; "/integrations": { parameters: { query?: never; diff --git a/packages/types/pocketbase/pocketbase-types.ts b/packages/types/pocketbase/pocketbase-types.ts index 59148902..b1e3df98 100644 --- a/packages/types/pocketbase/pocketbase-types.ts +++ b/packages/types/pocketbase/pocketbase-types.ts @@ -27,6 +27,7 @@ export const Collections = { NotificationTopicTokens: "notificationTopicTokens", PageConfig: "pageConfig", SearchItems: "searchItems", + Sessions: "sessions", Users: "users", WallpaperStore: "wallpaperStore", } as const @@ -327,6 +328,18 @@ export type SearchItemsRecord = { user?: RecordIdString } +export type SessionsRecord = { + clientType?: string + created: IsoAutoDateString + displayName: string + id: string + lastSeenAt: IsoDateString + platform?: string + sessionId: string + updated: IsoAutoDateString + user: RecordIdString +} + export type UsersRecord = { appearancePreferences?: null | TappearancePreferences avatar?: FileNameString @@ -376,6 +389,7 @@ export type NotificationTopicsResponse = Required = Required & BaseSystemFields export type PageConfigResponse = Required> & BaseSystemFields export type SearchItemsResponse = Required> & BaseSystemFields +export type SessionsResponse = Required & BaseSystemFields export type UsersResponse = Required> & AuthSystemFields export type WallpaperStoreResponse = Required & BaseSystemFields @@ -403,6 +417,7 @@ export type CollectionRecords = { notificationTopicTokens: NotificationTopicTokensRecord pageConfig: PageConfigRecord searchItems: SearchItemsRecord + sessions: SessionsRecord users: UsersRecord wallpaperStore: WallpaperStoreRecord } @@ -429,6 +444,7 @@ export type CollectionResponses = { notificationTopicTokens: NotificationTopicTokensResponse pageConfig: PageConfigResponse searchItems: SearchItemsResponse + sessions: SessionsResponse users: UsersResponse wallpaperStore: WallpaperStoreResponse } diff --git a/packages/types/sdk-types.ts b/packages/types/sdk-types.ts index 84262c52..0d994db5 100644 --- a/packages/types/sdk-types.ts +++ b/packages/types/sdk-types.ts @@ -1,5 +1,6 @@ export type ActionAuth = { token?: string | null; + sessionId?: string | null; }; export type JsonPrimitive = string | number | boolean | null; diff --git a/pocketbase/migrations/1785000003_created_sessions.js b/pocketbase/migrations/1785000003_created_sessions.js new file mode 100644 index 00000000..e234ade3 --- /dev/null +++ b/pocketbase/migrations/1785000003_created_sessions.js @@ -0,0 +1,138 @@ +/// +migrate((app) => { + const collection = new Collection({ + "createRule": "@request.auth.id = user", + "deleteRule": "@request.auth.id = user", + "fields": [ + { + "autogeneratePattern": "[a-z0-9]{15}", + "hidden": false, + "id": "text3208210256", + "max": 15, + "min": 15, + "name": "id", + "pattern": "^[a-z0-9]+$", + "presentable": false, + "primaryKey": true, + "required": true, + "system": true, + "type": "text" + }, + { + "cascadeDelete": true, + "collectionId": "_pb_users_auth_", + "hidden": false, + "id": "relation341user", + "maxSelect": 1, + "minSelect": 1, + "name": "user", + "presentable": false, + "required": true, + "system": false, + "type": "relation" + }, + { + "autogeneratePattern": "", + "hidden": false, + "id": "text341session", + "max": 128, + "min": 1, + "name": "sessionId", + "pattern": "^[A-Za-z0-9][A-Za-z0-9_-]{0,127}$", + "presentable": false, + "primaryKey": false, + "required": true, + "system": false, + "type": "text" + }, + { + "autogeneratePattern": "", + "hidden": false, + "id": "text341display", + "max": 100, + "min": 1, + "name": "displayName", + "pattern": "", + "presentable": true, + "primaryKey": false, + "required": true, + "system": false, + "type": "text" + }, + { + "autogeneratePattern": "", + "hidden": false, + "id": "text341client", + "max": 100, + "min": 0, + "name": "clientType", + "pattern": "", + "presentable": false, + "primaryKey": false, + "required": false, + "system": false, + "type": "text" + }, + { + "autogeneratePattern": "", + "hidden": false, + "id": "text341platform", + "max": 100, + "min": 0, + "name": "platform", + "pattern": "", + "presentable": false, + "primaryKey": false, + "required": false, + "system": false, + "type": "text" + }, + { + "hidden": false, + "id": "date341seenat", + "max": "", + "min": "", + "name": "lastSeenAt", + "presentable": false, + "required": true, + "system": false, + "type": "date" + }, + { + "hidden": false, + "id": "autodate2990389176", + "name": "created", + "onCreate": true, + "onUpdate": false, + "presentable": false, + "system": false, + "type": "autodate" + }, + { + "hidden": false, + "id": "autodate3332085495", + "name": "updated", + "onCreate": true, + "onUpdate": true, + "presentable": false, + "system": false, + "type": "autodate" + } + ], + "id": "pbc_341session", + "indexes": [ + "CREATE UNIQUE INDEX `idx_sessions_user_sessionId` ON `sessions` (`user`, `sessionId`)" + ], + "listRule": "@request.auth.id = user", + "name": "sessions", + "system": false, + "type": "base", + "updateRule": "@request.auth.id = user", + "viewRule": "@request.auth.id = user" + }); + + return app.save(collection); +}, (app) => { + const collection = app.findCollectionByNameOrId("pbc_341session"); + return app.delete(collection); +}); From 140a4053d54daabdb444341fe820c866b6afc6ee Mon Sep 17 00:00:00 2001 From: Andreas Molnar Date: Fri, 28 Aug 2026 21:21:28 +0200 Subject: [PATCH 2/3] fix: rename brightness filter in wallpaper settings --- apps/web/src/components/settings/WallpaperBrightnessSlider.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/web/src/components/settings/WallpaperBrightnessSlider.tsx b/apps/web/src/components/settings/WallpaperBrightnessSlider.tsx index 43522a48..7fc6fe3d 100644 --- a/apps/web/src/components/settings/WallpaperBrightnessSlider.tsx +++ b/apps/web/src/components/settings/WallpaperBrightnessSlider.tsx @@ -67,7 +67,7 @@ export default function WallpaperBrightnessSliderComponent({ className }: { clas )} >
-

Darken/Brighten

+

Brightness

From ec89aea84a93bebd840c8b50acd0d4bc6fcff081 Mon Sep 17 00:00:00 2001 From: Andreas Molnar Date: Fri, 28 Aug 2026 21:22:23 +0200 Subject: [PATCH 3/3] fix(account settings): use dialog for device name setting --- .../(authenticated)/settings/account/page.tsx | 106 ++++++++++++------ 1 file changed, 74 insertions(+), 32 deletions(-) diff --git a/apps/web/src/app/(authenticated)/settings/account/page.tsx b/apps/web/src/app/(authenticated)/settings/account/page.tsx index 332bb882..610f827f 100644 --- a/apps/web/src/app/(authenticated)/settings/account/page.tsx +++ b/apps/web/src/app/(authenticated)/settings/account/page.tsx @@ -20,9 +20,11 @@ import { changePasswordAction, deleteAccountAction } from '@/lib/apiClient'; import { getCurrentSessionAction, renameCurrentSessionAction } from '@/lib/apiClient'; import { DialogDescription } from "@radix-ui/react-dialog"; import useAuth from "@/context/useAuth"; -import { useMutation, useQuery } from "@tanstack/react-query"; +import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query"; import { queryKeys } from "@/lib/queryClient"; +const DEFAULT_SESSION_NAMES = new Set(["web browser"]); + export default function AccountSettingsPage() { const navigate = useNavigate(); const { user, token, setAuth, logout, withAuth } = useAuth(); @@ -38,6 +40,8 @@ export default function AccountSettingsPage() { const [deleteError, setDeleteError] = useState(null); const [sessionName, setSessionName] = useState(""); const [sessionError, setSessionError] = useState(null); + const [isDeviceNameDialogOpen, setIsDeviceNameDialogOpen] = useState(false); + const queryClient = useQueryClient(); const sessionQuery = useQuery({ queryKey: queryKeys.auth.session(token), enabled: Boolean(token), @@ -49,11 +53,13 @@ export default function AccountSettingsPage() { onSuccess: (session) => { setSessionName(session.displayName); setSessionError(null); + queryClient.setQueryData(queryKeys.auth.session(token), session); + setIsDeviceNameDialogOpen(false); }, }); useEffect(() => { - if (sessionQuery.data?.displayName) setSessionName(sessionQuery.data.displayName); + setSessionName(sessionQuery.data?.displayName ?? ""); }, [sessionQuery.data?.displayName]); const handleSessionNameSubmit = (event: React.FormEvent) => { @@ -69,6 +75,10 @@ export default function AccountSettingsPage() { }); }; + const normalizedSessionDisplayName = sessionQuery.data?.displayName?.trim().toLowerCase(); + const needsDeviceName = !normalizedSessionDisplayName || + DEFAULT_SESSION_NAMES.has(normalizedSessionDisplayName); + const handleChangePasswordSubmit = async ( e: React.FormEvent, ) => { @@ -177,32 +187,70 @@ export default function AccountSettingsPage() { {user?.name ?? "Lorem ipsum"} -
-
+

Authentication

+ + { + setIsDeviceNameDialogOpen(open); + if (open) { + setSessionName(sessionQuery.data?.displayName ?? ""); + setSessionError(null); + } + }} + > + -
-

device

-

name this browser so you can recognize it elsewhere in dashwise.

-
-
-
- - setSessionName(event.target.value)} - placeholder="web browser" - maxLength={100} - disabled={sessionQuery.isLoading || sessionMutation.isPending} - /> - -
- {sessionError &&

{sessionError}

} -
+

+ Change Device Name + {sessionQuery.isFetched && needsDeviceName && ( +

+ + -

Authentication

+ + + Change Device Name + + Set a name for this browser so you can recognize it elsewhere in Dashwise. + + + +
+
+ + setSessionName(event.target.value)} + placeholder="Web browser" + maxLength={100} + disabled={sessionQuery.isLoading || sessionMutation.isPending} + /> + {sessionError &&

{sessionError}

} +
+ + + + + + + +
+
+
@@ -289,12 +337,6 @@ export default function AccountSettingsPage() { -
- -

Multi-factor Authentication

- -
-