aboutsummaryrefslogtreecommitdiff
path: root/packages/lib
diff options
context:
space:
mode:
authorDhravya Shah <[email protected]>2025-09-18 20:34:18 -0700
committerDhravya Shah <[email protected]>2025-09-18 21:03:49 -0700
commit1fcb56908920da386900abb4ce2383374a625c72 (patch)
tree0f9d7f695d4c9b1b85be3950fc869e0061dff3ed /packages/lib
parentrefetching logic change (diff)
downloadsupermemory-09-18-formatting.tar.xz
supermemory-09-18-formatting.zip
Diffstat (limited to 'packages/lib')
-rw-r--r--packages/lib/api.ts18
-rw-r--r--packages/lib/auth-context.tsx77
-rw-r--r--packages/lib/auth.middleware.ts6
-rw-r--r--packages/lib/auth.ts14
-rw-r--r--packages/lib/constants.ts10
-rw-r--r--packages/lib/error-tracking.tsx103
-rw-r--r--packages/lib/generate-id.ts4
-rw-r--r--packages/lib/glass-effect-manager.ts196
-rw-r--r--packages/lib/posthog.tsx46
-rw-r--r--packages/lib/queries.ts94
-rw-r--r--packages/lib/query-client.tsx14
-rw-r--r--packages/lib/similarity.ts50
-rw-r--r--packages/lib/utils.ts8
13 files changed, 330 insertions, 310 deletions
diff --git a/packages/lib/api.ts b/packages/lib/api.ts
index ad343050..82c0b8ef 100644
--- a/packages/lib/api.ts
+++ b/packages/lib/api.ts
@@ -10,6 +10,7 @@ import {
DeleteProjectSchema,
DocumentsWithMemoriesQuerySchema,
DocumentsWithMemoriesResponseSchema,
+ GetMemoryResponseSchema,
ListMemoriesResponseSchema,
ListProjectsResponseSchema,
MemoryAddSchema,
@@ -126,7 +127,24 @@ export const apiSchema = createSchema({
input: SettingsRequestSchema,
output: SettingsResponseSchema,
},
+
+ "@get/documents/:id": {
+ output: GetMemoryResponseSchema,
+ params: z.object({ id: z.string() }),
+ },
+
// Memory operations
+ "@get/documents": {
+ output: ListMemoriesResponseSchema,
+ query: z
+ .object({
+ limit: z.number().optional(),
+ page: z.number().optional(),
+ status: z.string().optional(),
+ containerTags: z.array(z.string()).optional(),
+ })
+ .optional(),
+ },
"@post/documents": {
input: MemoryAddSchema,
output: MemoryResponseSchema,
diff --git a/packages/lib/auth-context.tsx b/packages/lib/auth-context.tsx
index 66ff84bc..a88c73c8 100644
--- a/packages/lib/auth-context.tsx
+++ b/packages/lib/auth-context.tsx
@@ -1,4 +1,4 @@
-"use client"
+"use client";
import {
createContext,
@@ -6,75 +6,74 @@ import {
useContext,
useEffect,
useState,
-} from "react"
-import { authClient, useSession } from "./auth"
+} from "react";
+import { authClient, useSession } from "./auth";
-type Organization = typeof authClient.$Infer.ActiveOrganization
-type SessionData = NonNullable<ReturnType<typeof useSession>["data"]>
+type Organization = typeof authClient.$Infer.ActiveOrganization;
+type SessionData = NonNullable<ReturnType<typeof useSession>["data"]>;
interface AuthContextType {
- session: SessionData["session"] | null
- user: SessionData["user"] | null
- org: Organization | null
- setActiveOrg: (orgSlug: string) => Promise<void>
+ session: SessionData["session"] | null;
+ user: SessionData["user"] | null;
+ org: Organization | null;
+ setActiveOrg: (orgSlug: string) => Promise<void>;
}
-const AuthContext = createContext<AuthContextType | undefined>(undefined)
+const AuthContext = createContext<AuthContextType | undefined>(undefined);
export function AuthProvider({ children }: { children: ReactNode }) {
- const { data: session } = useSession()
- const [org, setOrg] = useState<Organization | null>(null)
+ const { data: session } = useSession();
+ const [org, setOrg] = useState<Organization | null>(null);
useEffect(() => {
if (session?.session.activeOrganizationId) {
authClient.organization.getFullOrganization().then((org) => {
- setOrg(org)
- })
+ setOrg(org);
+ });
}
- }, [session?.session.activeOrganizationId])
+ }, [session?.session.activeOrganizationId]);
// When a session exists and there is a pending login method recorded,
// promote it to the last-used method (successful login) and clear pending.
useEffect(() => {
- if (typeof window === "undefined") return
- if (!session?.session) return
+ if (typeof window === "undefined") return;
+ if (!session?.session) return;
try {
const pendingMethod = localStorage.getItem(
"supermemory-pending-login-method",
- )
+ );
const pendingTsRaw = localStorage.getItem(
"supermemory-pending-login-timestamp",
- )
+ );
if (pendingMethod) {
- const now = Date.now()
- const ts = pendingTsRaw ? Number.parseInt(pendingTsRaw, 10) : NaN
- const isFresh = Number.isFinite(ts) && now - ts < 10 * 60 * 1000 // 10 minutes TTL
+ const now = Date.now();
+ const ts = pendingTsRaw
+ ? Number.parseInt(pendingTsRaw, 10)
+ : Number.NaN;
+ const isFresh = Number.isFinite(ts) && now - ts < 10 * 60 * 1000; // 10 minutes TTL
if (isFresh) {
- localStorage.setItem(
- "supermemory-last-login-method",
- pendingMethod,
- )
+ localStorage.setItem("supermemory-last-login-method", pendingMethod);
}
}
- } catch { }
+ } catch {}
// Always clear pending markers once a session is present
try {
- localStorage.removeItem("supermemory-pending-login-method")
- localStorage.removeItem("supermemory-pending-login-timestamp")
- } catch { }
- }, [session?.session])
+ localStorage.removeItem("supermemory-pending-login-method");
+ localStorage.removeItem("supermemory-pending-login-timestamp");
+ } catch {}
+ }, [session?.session]);
const setActiveOrg = async (slug: string) => {
- if (!slug) return
+ if (!slug) return;
const activeOrg = await authClient.organization.setActive({
organizationSlug: slug,
- })
- setOrg(activeOrg)
- }
+ });
+ setOrg(activeOrg);
+ };
return (
<AuthContext.Provider
@@ -87,13 +86,13 @@ export function AuthProvider({ children }: { children: ReactNode }) {
>
{children}
</AuthContext.Provider>
- )
+ );
}
export function useAuth() {
- const context = useContext(AuthContext)
+ const context = useContext(AuthContext);
if (context === undefined) {
- throw new Error("useAuth must be used within an AuthProvider")
+ throw new Error("useAuth must be used within an AuthProvider");
}
- return context
+ return context;
}
diff --git a/packages/lib/auth.middleware.ts b/packages/lib/auth.middleware.ts
index 3b1f1f40..884f14b8 100644
--- a/packages/lib/auth.middleware.ts
+++ b/packages/lib/auth.middleware.ts
@@ -1,4 +1,4 @@
-import { createAuthClient } from "better-auth/client"
+import { createAuthClient } from "better-auth/client";
import {
adminClient,
anonymousClient,
@@ -7,7 +7,7 @@ import {
magicLinkClient,
organizationClient,
usernameClient,
-} from "better-auth/client/plugins"
+} from "better-auth/client/plugins";
export const middlewareAuthClient = createAuthClient({
baseURL: process.env.NEXT_PUBLIC_BACKEND_URL ?? "https://api.supermemory.ai",
@@ -23,4 +23,4 @@ export const middlewareAuthClient = createAuthClient({
organizationClient(),
anonymousClient(),
],
-})
+});
diff --git a/packages/lib/auth.ts b/packages/lib/auth.ts
index 4369bef1..02709e2c 100644
--- a/packages/lib/auth.ts
+++ b/packages/lib/auth.ts
@@ -6,8 +6,8 @@ import {
magicLinkClient,
organizationClient,
usernameClient,
-} from "better-auth/client/plugins"
-import { createAuthClient } from "better-auth/react"
+} from "better-auth/client/plugins";
+import { createAuthClient } from "better-auth/react";
export const authClient = createAuthClient({
baseURL: process.env.NEXT_PUBLIC_BACKEND_URL ?? "https://api.supermemory.ai",
@@ -24,9 +24,9 @@ export const authClient = createAuthClient({
organizationClient(),
anonymousClient(),
],
-})
+});
-export const signIn = authClient.signIn
-export const signOut = authClient.signOut
-export const useSession = authClient.useSession
-export const getSession = authClient.getSession
+export const signIn = authClient.signIn;
+export const signOut = authClient.signOut;
+export const useSession = authClient.useSession;
+export const getSession = authClient.getSession;
diff --git a/packages/lib/constants.ts b/packages/lib/constants.ts
index fde5bce1..74eb27ec 100644
--- a/packages/lib/constants.ts
+++ b/packages/lib/constants.ts
@@ -1,13 +1,13 @@
-const BIG_DIMENSIONS_NEW = 1536
-const DEFAULT_PROJECT_ID = "sm_project_default"
+const BIG_DIMENSIONS_NEW = 1536;
+const DEFAULT_PROJECT_ID = "sm_project_default";
const SEARCH_MEMORY_SHORTCUT_URL =
- "https://www.icloud.com/shortcuts/f2b5c544372844a38ab4c6900e2a88de"
+ "https://www.icloud.com/shortcuts/f2b5c544372844a38ab4c6900e2a88de";
const ADD_MEMORY_SHORTCUT_URL =
- "https://www.icloud.com/shortcuts/ec33b029b2c7481d89eda7640dbb7688"
+ "https://www.icloud.com/shortcuts/ec33b029b2c7481d89eda7640dbb7688";
export {
BIG_DIMENSIONS_NEW,
DEFAULT_PROJECT_ID,
SEARCH_MEMORY_SHORTCUT_URL,
ADD_MEMORY_SHORTCUT_URL,
-}
+};
diff --git a/packages/lib/error-tracking.tsx b/packages/lib/error-tracking.tsx
index bf320271..cc3a9b3c 100644
--- a/packages/lib/error-tracking.tsx
+++ b/packages/lib/error-tracking.tsx
@@ -1,14 +1,14 @@
-"use client"
+"use client";
-import { usePathname } from "next/navigation"
-import { useEffect } from "react"
-import { useSession } from "./auth"
-import { usePostHog } from "./posthog"
+import { usePathname } from "next/navigation";
+import { useEffect } from "react";
+import { useSession } from "./auth";
+import { usePostHog } from "./posthog";
export function useErrorTracking() {
- const posthog = usePostHog()
- const { data: session } = useSession()
- const pathname = usePathname()
+ const posthog = usePostHog();
+ const { data: session } = useSession();
+ const pathname = usePathname();
const trackError = (
error: Error | unknown,
@@ -23,10 +23,10 @@ export function useErrorTracking() {
user_email: session?.user?.email,
timestamp: new Date().toISOString(),
...context,
- }
+ };
- posthog.capture("error_occurred", errorDetails)
- }
+ posthog.capture("error_occurred", errorDetails);
+ };
const trackApiError = (
error: Error | unknown,
@@ -37,8 +37,8 @@ export function useErrorTracking() {
error_type: "api_error",
api_endpoint: endpoint,
api_method: method,
- })
- }
+ });
+ };
const trackComponentError = (
error: Error | unknown,
@@ -47,8 +47,8 @@ export function useErrorTracking() {
trackError(error, {
error_type: "component_error",
component_name: componentName,
- })
- }
+ });
+ };
const trackValidationError = (
error: Error | unknown,
@@ -59,24 +59,24 @@ export function useErrorTracking() {
error_type: "validation_error",
form_name: formName,
field_name: field,
- })
- }
+ });
+ };
return {
trackError,
trackApiError,
trackComponentError,
trackValidationError,
- }
+ };
}
// Global error boundary component
export function ErrorTrackingProvider({
children,
}: {
- children: React.ReactNode
+ children: React.ReactNode;
}) {
- const { trackError } = useErrorTracking()
+ const { trackError } = useErrorTracking();
useEffect(() => {
// Global error handler for unhandled errors
@@ -87,34 +87,37 @@ export function ErrorTrackingProvider({
filename: event.filename,
lineno: event.lineno,
colno: event.colno,
- })
- }
+ });
+ };
// Global handler for unhandled promise rejections
const handleUnhandledRejection = (event: PromiseRejectionEvent) => {
trackError(event.reason, {
error_type: "unhandled_promise_rejection",
source: "promise_rejection",
- })
- }
+ });
+ };
- window.addEventListener("error", handleError)
- window.addEventListener("unhandledrejection", handleUnhandledRejection)
+ window.addEventListener("error", handleError);
+ window.addEventListener("unhandledrejection", handleUnhandledRejection);
return () => {
- window.removeEventListener("error", handleError)
- window.removeEventListener("unhandledrejection", handleUnhandledRejection)
- }
- }, [trackError])
-
- return <>{children}</>
+ window.removeEventListener("error", handleError);
+ window.removeEventListener(
+ "unhandledrejection",
+ handleUnhandledRejection,
+ );
+ };
+ }, [trackError]);
+
+ return <>{children}</>;
}
// Hook for tracking user interactions
export function useInteractionTracking() {
- const posthog = usePostHog()
- const { data: session } = useSession()
- const pathname = usePathname()
+ const posthog = usePostHog();
+ const { data: session } = useSession();
+ const pathname = usePathname();
const trackInteraction = (action: string, details?: Record<string, any>) => {
posthog.capture("user_interaction", {
@@ -123,8 +126,8 @@ export function useInteractionTracking() {
user_id: session?.user?.id,
timestamp: new Date().toISOString(),
...details,
- })
- }
+ });
+ };
const trackFormSubmission = (
formName: string,
@@ -138,15 +141,15 @@ export function useInteractionTracking() {
user_id: session?.user?.id,
timestamp: new Date().toISOString(),
...details,
- })
- }
+ });
+ };
const trackButtonClick = (buttonName: string, context?: string) => {
trackInteraction("button_click", {
button_name: buttonName,
context,
- })
- }
+ });
+ };
const trackLinkClick = (
url: string,
@@ -157,27 +160,27 @@ export function useInteractionTracking() {
url,
link_text: linkText,
external,
- })
- }
+ });
+ };
const trackModalOpen = (modalName: string) => {
trackInteraction("modal_open", {
modal_name: modalName,
- })
- }
+ });
+ };
const trackModalClose = (modalName: string) => {
trackInteraction("modal_close", {
modal_name: modalName,
- })
- }
+ });
+ };
const trackTabChange = (fromTab: string, toTab: string) => {
trackInteraction("tab_change", {
from_tab: fromTab,
to_tab: toTab,
- })
- }
+ });
+ };
return {
trackInteraction,
@@ -187,5 +190,5 @@ export function useInteractionTracking() {
trackModalOpen,
trackModalClose,
trackTabChange,
- }
+ };
}
diff --git a/packages/lib/generate-id.ts b/packages/lib/generate-id.ts
index bbe201fd..6007027e 100644
--- a/packages/lib/generate-id.ts
+++ b/packages/lib/generate-id.ts
@@ -1,6 +1,6 @@
-import { customAlphabet } from "nanoid"
+import { customAlphabet } from "nanoid";
export const generateId = () =>
customAlphabet("123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz")(
22,
- )
+ );
diff --git a/packages/lib/glass-effect-manager.ts b/packages/lib/glass-effect-manager.ts
index 291a30aa..03a79734 100644
--- a/packages/lib/glass-effect-manager.ts
+++ b/packages/lib/glass-effect-manager.ts
@@ -1,56 +1,56 @@
// Singleton WebGL context manager for glass effects
class GlassEffectManager {
- private static instance: GlassEffectManager | null = null
- private canvas: HTMLCanvasElement | null = null
- private gl: WebGLRenderingContext | null = null
- private program: WebGLProgram | null = null
- private uniforms: Record<string, WebGLUniformLocation | null> = {}
- private effects: Map<string, EffectInstance> = new Map()
- private animationFrame: number | null = null
- private startTime: number = performance.now()
- private mousePositions: Map<string, { x: number; y: number }> = new Map()
+ private static instance: GlassEffectManager | null = null;
+ private canvas: HTMLCanvasElement | null = null;
+ private gl: WebGLRenderingContext | null = null;
+ private program: WebGLProgram | null = null;
+ private uniforms: Record<string, WebGLUniformLocation | null> = {};
+ private effects: Map<string, EffectInstance> = new Map();
+ private animationFrame: number | null = null;
+ private startTime: number = performance.now();
+ private mousePositions: Map<string, { x: number; y: number }> = new Map();
static getInstance(): GlassEffectManager {
if (!GlassEffectManager.instance) {
- GlassEffectManager.instance = new GlassEffectManager()
+ GlassEffectManager.instance = new GlassEffectManager();
}
- return GlassEffectManager.instance
+ return GlassEffectManager.instance;
}
private constructor() {
- this.initializeContext()
+ this.initializeContext();
}
private initializeContext() {
// Create offscreen canvas
- this.canvas = document.createElement("canvas")
- this.canvas.width = 1024 // Default size, will be adjusted
- this.canvas.height = 1024
+ this.canvas = document.createElement("canvas");
+ this.canvas.width = 1024; // Default size, will be adjusted
+ this.canvas.height = 1024;
this.gl = this.canvas.getContext("webgl", {
alpha: true,
premultipliedAlpha: false,
preserveDrawingBuffer: true,
- })
+ });
if (!this.gl) {
- console.error("WebGL not supported")
- return
+ console.error("WebGL not supported");
+ return;
}
- this.setupShaders()
- this.startRenderLoop()
+ this.setupShaders();
+ this.startRenderLoop();
}
private setupShaders() {
- if (!this.gl) return
+ if (!this.gl) return;
const vsSource = `
attribute vec2 position;
void main() {
gl_Position = vec4(position, 0.0, 1.0);
}
- `
+ `;
const fsSource = `
precision mediump float;
@@ -106,48 +106,48 @@ class GlassEffectManager {
gl_FragColor = vec4(glassColor, alpha);
}
- `
+ `;
const createShader = (type: number, source: string) => {
- const shader = this.gl!.createShader(type)
- if (!shader) return null
+ const shader = this.gl!.createShader(type);
+ if (!shader) return null;
- this.gl!.shaderSource(shader, source)
- this.gl!.compileShader(shader)
+ this.gl!.shaderSource(shader, source);
+ this.gl!.compileShader(shader);
if (!this.gl!.getShaderParameter(shader, this.gl!.COMPILE_STATUS)) {
- console.error("Shader error:", this.gl!.getShaderInfoLog(shader))
- this.gl!.deleteShader(shader)
- return null
+ console.error("Shader error:", this.gl!.getShaderInfoLog(shader));
+ this.gl!.deleteShader(shader);
+ return null;
}
- return shader
- }
+ return shader;
+ };
- const vs = createShader(this.gl.VERTEX_SHADER, vsSource)
- const fs = createShader(this.gl.FRAGMENT_SHADER, fsSource)
- if (!vs || !fs) return
+ const vs = createShader(this.gl.VERTEX_SHADER, vsSource);
+ const fs = createShader(this.gl.FRAGMENT_SHADER, fsSource);
+ if (!vs || !fs) return;
- this.program = this.gl.createProgram()
- if (!this.program) return
+ this.program = this.gl.createProgram();
+ if (!this.program) return;
- this.gl.attachShader(this.program, vs)
- this.gl.attachShader(this.program, fs)
- this.gl.linkProgram(this.program)
+ this.gl.attachShader(this.program, vs);
+ this.gl.attachShader(this.program, fs);
+ this.gl.linkProgram(this.program);
// biome-ignore lint/correctness/useHookAtTopLevel: Well, not a hook
- this.gl.useProgram(this.program)
+ this.gl.useProgram(this.program);
// Buffer setup
- const buffer = this.gl.createBuffer()
- this.gl.bindBuffer(this.gl.ARRAY_BUFFER, buffer)
+ const buffer = this.gl.createBuffer();
+ this.gl.bindBuffer(this.gl.ARRAY_BUFFER, buffer);
this.gl.bufferData(
this.gl.ARRAY_BUFFER,
new Float32Array([-1, -1, 1, -1, -1, 1, 1, 1]),
this.gl.STATIC_DRAW,
- )
+ );
- const position = this.gl.getAttribLocation(this.program, "position")
- this.gl.enableVertexAttribArray(position)
- this.gl.vertexAttribPointer(position, 2, this.gl.FLOAT, false, 0, 0)
+ const position = this.gl.getAttribLocation(this.program, "position");
+ this.gl.enableVertexAttribArray(position);
+ this.gl.vertexAttribPointer(position, 2, this.gl.FLOAT, false, 0, 0);
// Store uniform locations
this.uniforms = {
@@ -155,11 +155,11 @@ class GlassEffectManager {
time: this.gl.getUniformLocation(this.program, "iTime"),
mouse: this.gl.getUniformLocation(this.program, "iMouse"),
expanded: this.gl.getUniformLocation(this.program, "iExpanded"),
- }
+ };
// Enable blending
- this.gl.enable(this.gl.BLEND)
- this.gl.blendFunc(this.gl.SRC_ALPHA, this.gl.ONE_MINUS_SRC_ALPHA)
+ this.gl.enable(this.gl.BLEND);
+ this.gl.blendFunc(this.gl.SRC_ALPHA, this.gl.ONE_MINUS_SRC_ALPHA);
}
registerEffect(
@@ -168,8 +168,8 @@ class GlassEffectManager {
isExpanded: boolean,
): () => void {
// Ensure minimum dimensions
- const width = Math.max(1, targetCanvas.width)
- const height = Math.max(1, targetCanvas.height)
+ const width = Math.max(1, targetCanvas.width);
+ const height = Math.max(1, targetCanvas.height);
const effect: EffectInstance = {
id,
@@ -177,58 +177,58 @@ class GlassEffectManager {
isExpanded,
width,
height,
- }
+ };
- this.effects.set(id, effect)
- this.mousePositions.set(id, { x: 0, y: 0 })
+ this.effects.set(id, effect);
+ this.mousePositions.set(id, { x: 0, y: 0 });
// Return cleanup function
return () => {
- this.effects.delete(id)
- this.mousePositions.delete(id)
+ this.effects.delete(id);
+ this.mousePositions.delete(id);
if (this.effects.size === 0 && this.animationFrame) {
- cancelAnimationFrame(this.animationFrame)
- this.animationFrame = null
+ cancelAnimationFrame(this.animationFrame);
+ this.animationFrame = null;
}
- }
+ };
}
updateMousePosition(id: string, x: number, y: number) {
- this.mousePositions.set(id, { x, y })
+ this.mousePositions.set(id, { x, y });
}
updateExpanded(id: string, isExpanded: boolean) {
- const effect = this.effects.get(id)
+ const effect = this.effects.get(id);
if (effect) {
- effect.isExpanded = isExpanded
+ effect.isExpanded = isExpanded;
}
}
updateSize(id: string, width: number, height: number) {
- const effect = this.effects.get(id)
+ const effect = this.effects.get(id);
if (effect) {
// Ensure minimum dimensions
- effect.width = Math.max(1, width)
- effect.height = Math.max(1, height)
+ effect.width = Math.max(1, width);
+ effect.height = Math.max(1, height);
}
}
private startRenderLoop() {
const render = () => {
if (!this.gl || !this.program || this.effects.size === 0) {
- this.animationFrame = requestAnimationFrame(render)
- return
+ this.animationFrame = requestAnimationFrame(render);
+ return;
}
- const currentTime = (performance.now() - this.startTime) / 1000
+ const currentTime = (performance.now() - this.startTime) / 1000;
// Render each effect
for (const [id, effect] of Array.from(this.effects)) {
- const mousePos = this.mousePositions.get(id) || { x: 0, y: 0 }
+ const mousePos = this.mousePositions.get(id) || { x: 0, y: 0 };
// Skip rendering if dimensions are invalid
if (effect.width <= 0 || effect.height <= 0) {
- continue
+ continue;
}
// Set canvas size if needed
@@ -236,14 +236,14 @@ class GlassEffectManager {
this.canvas!.width !== effect.width ||
this.canvas!.height !== effect.height
) {
- this.canvas!.width = effect.width
- this.canvas!.height = effect.height
- this.gl.viewport(0, 0, effect.width, effect.height)
+ this.canvas!.width = effect.width;
+ this.canvas!.height = effect.height;
+ this.gl.viewport(0, 0, effect.width, effect.height);
}
// Clear and render
- this.gl.clearColor(0, 0, 0, 0)
- this.gl.clear(this.gl.COLOR_BUFFER_BIT)
+ this.gl.clearColor(0, 0, 0, 0);
+ this.gl.clear(this.gl.COLOR_BUFFER_BIT);
// Set uniforms
if (this.uniforms.resolution) {
@@ -251,58 +251,58 @@ class GlassEffectManager {
this.uniforms.resolution,
effect.width,
effect.height,
- )
+ );
}
if (this.uniforms.time) {
- this.gl.uniform1f(this.uniforms.time, currentTime)
+ this.gl.uniform1f(this.uniforms.time, currentTime);
}
if (this.uniforms.mouse) {
- this.gl.uniform2f(this.uniforms.mouse, mousePos.x, mousePos.y)
+ this.gl.uniform2f(this.uniforms.mouse, mousePos.x, mousePos.y);
}
if (this.uniforms.expanded) {
this.gl.uniform1f(
this.uniforms.expanded,
effect.isExpanded ? 1.0 : 0.0,
- )
+ );
}
// Draw
- this.gl.drawArrays(this.gl.TRIANGLE_STRIP, 0, 4)
+ this.gl.drawArrays(this.gl.TRIANGLE_STRIP, 0, 4);
// Copy to target canvas
- const targetCtx = effect.targetCanvas.getContext("2d")
+ const targetCtx = effect.targetCanvas.getContext("2d");
if (targetCtx) {
- targetCtx.clearRect(0, 0, effect.width, effect.height)
- targetCtx.drawImage(this.canvas!, 0, 0)
+ targetCtx.clearRect(0, 0, effect.width, effect.height);
+ targetCtx.drawImage(this.canvas!, 0, 0);
}
}
- this.animationFrame = requestAnimationFrame(render)
- }
+ this.animationFrame = requestAnimationFrame(render);
+ };
- render()
+ render();
}
// Clean up method (optional, for when the app unmounts)
destroy() {
if (this.animationFrame) {
- cancelAnimationFrame(this.animationFrame)
+ cancelAnimationFrame(this.animationFrame);
}
if (this.gl && this.program) {
- this.gl.deleteProgram(this.program)
+ this.gl.deleteProgram(this.program);
}
- this.effects.clear()
- this.mousePositions.clear()
- GlassEffectManager.instance = null
+ this.effects.clear();
+ this.mousePositions.clear();
+ GlassEffectManager.instance = null;
}
}
interface EffectInstance {
- id: string
- targetCanvas: HTMLCanvasElement
- isExpanded: boolean
- width: number
- height: number
+ id: string;
+ targetCanvas: HTMLCanvasElement;
+ isExpanded: boolean;
+ width: number;
+ height: number;
}
-export default GlassEffectManager
+export default GlassEffectManager;
diff --git a/packages/lib/posthog.tsx b/packages/lib/posthog.tsx
index ac563aae..d1105cbc 100644
--- a/packages/lib/posthog.tsx
+++ b/packages/lib/posthog.tsx
@@ -1,20 +1,20 @@
-"use client"
+"use client";
-import { usePathname, useSearchParams } from "next/navigation"
-import posthog from "posthog-js"
-import { Suspense, useEffect } from "react"
-import { useSession } from "./auth"
+import { usePathname, useSearchParams } from "next/navigation";
+import posthog from "posthog-js";
+import { Suspense, useEffect } from "react";
+import { useSession } from "./auth";
function PostHogPageTracking() {
- const pathname = usePathname()
- const searchParams = useSearchParams()
+ const pathname = usePathname();
+ const searchParams = useSearchParams();
// Page tracking
useEffect(() => {
if (pathname) {
- let url = window.origin + pathname
+ let url = window.origin + pathname;
if (searchParams.toString()) {
- url = `${url}?${searchParams.toString()}`
+ url = `${url}?${searchParams.toString()}`;
}
// Extract page context for better tracking
@@ -24,17 +24,17 @@ function PostHogPageTracking() {
search_params: searchParams.toString(),
page_type: getPageType(pathname),
org_slug: getOrgSlug(pathname),
- }
+ };
- posthog.capture("$pageview", pageContext)
+ posthog.capture("$pageview", pageContext);
}
- }, [pathname, searchParams])
+ }, [pathname, searchParams]);
- return null
+ return null;
}
export function PostHogProvider({ children }: { children: React.ReactNode }) {
- const { data: session } = useSession()
+ const { data: session } = useSession();
useEffect(() => {
if (typeof window !== "undefined") {
@@ -44,9 +44,9 @@ export function PostHogProvider({ children }: { children: React.ReactNode }) {
person_profiles: "identified_only",
capture_pageview: false,
capture_pageleave: true,
- })
+ });
}
- }, [])
+ }, []);
// User identification
useEffect(() => {
@@ -56,9 +56,9 @@ export function PostHogProvider({ children }: { children: React.ReactNode }) {
name: session.user.name,
userId: session.user.id,
createdAt: session.user.createdAt,
- })
+ });
}
- }, [session?.user])
+ }, [session?.user]);
return (
<>
@@ -67,18 +67,18 @@ export function PostHogProvider({ children }: { children: React.ReactNode }) {
</Suspense>
{children}
</>
- )
+ );
}
function getPageType(pathname: string): string {
- return "other"
+ return "other";
}
function getOrgSlug(pathname: string): string | null {
- const match = pathname.match(/^\/([^/]+)\//)
- return match ? (match[1] ?? null) : null
+ const match = pathname.match(/^\/([^/]+)\//);
+ return match ? (match[1] ?? null) : null;
}
export function usePostHog() {
- return posthog
+ return posthog;
}
diff --git a/packages/lib/queries.ts b/packages/lib/queries.ts
index 3e9e1ab9..d0f93915 100644
--- a/packages/lib/queries.ts
+++ b/packages/lib/queries.ts
@@ -1,12 +1,12 @@
-import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query"
-import type { useCustomer } from "autumn-js/react"
-import { toast } from "sonner"
-import type { z } from "zod"
-import type { DocumentsWithMemoriesResponseSchema } from "../validation/api"
-import { $fetch } from "./api"
+import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
+import type { useCustomer } from "autumn-js/react";
+import { toast } from "sonner";
+import type { z } from "zod";
+import type { DocumentsWithMemoriesResponseSchema } from "../validation/api";
+import { $fetch } from "./api";
-type DocumentsResponse = z.infer<typeof DocumentsWithMemoriesResponseSchema>
-type DocumentWithMemories = DocumentsResponse["documents"][0]
+type DocumentsResponse = z.infer<typeof DocumentsWithMemoriesResponseSchema>;
+type DocumentWithMemories = DocumentsResponse["documents"][0];
export const fetchSubscriptionStatus = (
autumn: ReturnType<typeof useCustomer>,
@@ -18,54 +18,54 @@ export const fetchSubscriptionStatus = (
"memory_starter",
"memory_growth",
"consumer_pro",
- ]
- const statusMap: Record<string, boolean | null> = {}
+ ];
+ const statusMap: Record<string, boolean | null> = {};
await Promise.all(
allPlans.map(async (plan) => {
try {
const res = await autumn.check({
productId: plan,
- })
- statusMap[plan] = res.data?.allowed ?? false
+ });
+ statusMap[plan] = res.data?.allowed ?? false;
} catch (error) {
- console.error(`Error checking status for ${plan}:`, error)
- statusMap[plan] = false
+ console.error(`Error checking status for ${plan}:`, error);
+ statusMap[plan] = false;
}
}),
- )
+ );
- return statusMap
+ return statusMap;
},
queryKey: ["subscription-status"],
refetchInterval: 5000, // Refetch every 5 seconds
staleTime: 4000, // Consider data stale after 4 seconds
- })
+ });
// Feature checks
export const fetchMemoriesFeature = (autumn: ReturnType<typeof useCustomer>) =>
useQuery({
queryFn: async () => {
- const res = await autumn.check({ featureId: "memories" })
- return res.data
+ const res = await autumn.check({ featureId: "memories" });
+ return res.data;
},
queryKey: ["autumn-feature", "memories"],
staleTime: 30 * 1000, // 30 seconds
gcTime: 5 * 60 * 1000, // 5 minutes
- })
+ });
export const fetchConnectionsFeature = (
autumn: ReturnType<typeof useCustomer>,
) =>
useQuery({
queryFn: async () => {
- const res = await autumn.check({ featureId: "connections" })
- return res.data
+ const res = await autumn.check({ featureId: "connections" });
+ return res.data;
},
queryKey: ["autumn-feature", "connections"],
staleTime: 30 * 1000, // 30 seconds
gcTime: 5 * 60 * 1000, // 5 minutes
- })
+ });
// Product checks
export const fetchConsumerProProduct = (
@@ -73,54 +73,54 @@ export const fetchConsumerProProduct = (
) =>
useQuery({
queryFn: async () => {
- const res = await autumn.check({ productId: "consumer_pro" })
- return res.data
+ const res = await autumn.check({ productId: "consumer_pro" });
+ return res.data;
},
queryKey: ["autumn-product", "consumer_pro"],
staleTime: 30 * 1000, // 30 seconds
gcTime: 5 * 60 * 1000, // 5 minutes
- })
+ });
export const fetchProProduct = (autumn: ReturnType<typeof useCustomer>) =>
useQuery({
queryFn: async () => {
- const res = await autumn.check({ productId: "pro" })
- return res.data
+ const res = await autumn.check({ productId: "pro" });
+ return res.data;
},
queryKey: ["autumn-product", "pro"],
staleTime: 30 * 1000, // 30 seconds
gcTime: 5 * 60 * 1000, // 5 minutes
- })
+ });
export const useDeleteDocument = (selectedProject: string) => {
- const queryClient = useQueryClient()
+ const queryClient = useQueryClient();
return useMutation({
mutationFn: async (documentId: string) => {
// context for LLM: delete/memories/:documentId is documents delete endpoint not memories delete endpoint
- const response = await $fetch(`@delete/documents/${documentId}`)
+ const response = await $fetch(`@delete/documents/${documentId}`);
if (response.error) {
- throw new Error(response.error?.message || "Failed to delete document")
+ throw new Error(response.error?.message || "Failed to delete document");
}
- return response.data
+ return response.data;
},
onMutate: async (documentId: string) => {
await queryClient.cancelQueries({
queryKey: ["documents-with-memories", selectedProject],
- })
+ });
const previousData = queryClient.getQueryData([
"documents-with-memories",
selectedProject,
- ])
+ ]);
queryClient.setQueryData(
["documents-with-memories", selectedProject],
(old: unknown) => {
- if (!old || typeof old !== "object") return old
+ if (!old || typeof old !== "object") return old;
const typedOld = old as {
- pages?: Array<{ documents?: DocumentWithMemories[] }>
- }
+ pages?: Array<{ documents?: DocumentWithMemories[] }>;
+ };
return {
...typedOld,
pages: typedOld.pages?.map((page) => ({
@@ -129,30 +129,30 @@ export const useDeleteDocument = (selectedProject: string) => {
(doc: DocumentWithMemories) => doc.id !== documentId,
),
})),
- }
+ };
},
- )
+ );
- return { previousData }
+ return { previousData };
},
onSuccess: () => {
- toast.success("Memory deleted successfully")
+ toast.success("Memory deleted successfully");
},
onError: (error, _documentId, context) => {
if (context?.previousData) {
queryClient.setQueryData(
["documents-with-memories", selectedProject],
context.previousData,
- )
+ );
}
toast.error("Failed to delete memory", {
description: error instanceof Error ? error.message : "Unknown error",
- })
+ });
},
onSettled: () => {
queryClient.invalidateQueries({
queryKey: ["documents-with-memories", selectedProject],
- })
+ });
},
- })
-}
+ });
+};
diff --git a/packages/lib/query-client.tsx b/packages/lib/query-client.tsx
index eb9c5a21..322e9f89 100644
--- a/packages/lib/query-client.tsx
+++ b/packages/lib/query-client.tsx
@@ -1,8 +1,8 @@
-"use client"
+"use client";
-import { QueryClient, QueryClientProvider } from "@tanstack/react-query"
-import { ReactQueryDevtools } from "@tanstack/react-query-devtools"
-import { useState } from "react"
+import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
+import { ReactQueryDevtools } from "@tanstack/react-query-devtools";
+import { useState } from "react";
export const QueryProvider = ({ children }: { children: React.ReactNode }) => {
const [queryClient] = useState(
@@ -16,12 +16,12 @@ export const QueryProvider = ({ children }: { children: React.ReactNode }) => {
},
},
}),
- )
+ );
return (
<QueryClientProvider client={queryClient}>
{children}
<ReactQueryDevtools initialIsOpen={false} />
</QueryClientProvider>
- )
-}
+ );
+};
diff --git a/packages/lib/similarity.ts b/packages/lib/similarity.ts
index 09d3a2cc..0d43710d 100644
--- a/packages/lib/similarity.ts
+++ b/packages/lib/similarity.ts
@@ -10,27 +10,27 @@ export const cosineSimilarity = (
vectorB: number[],
): number => {
if (vectorA.length !== vectorB.length) {
- throw new Error("Vectors must have the same length")
+ throw new Error("Vectors must have the same length");
}
- let dotProduct = 0
+ let dotProduct = 0;
for (let i = 0; i < vectorA.length; i++) {
- const vectorAi = vectorA[i]
- const vectorBi = vectorB[i]
+ const vectorAi = vectorA[i];
+ const vectorBi = vectorB[i];
if (
typeof vectorAi !== "number" ||
typeof vectorBi !== "number" ||
isNaN(vectorAi) ||
isNaN(vectorBi)
) {
- throw new Error("Vectors must contain only numbers")
+ throw new Error("Vectors must contain only numbers");
}
- dotProduct += vectorAi * vectorBi
+ dotProduct += vectorAi * vectorBi;
}
- return dotProduct
-}
+ return dotProduct;
+};
/**
* Calculate semantic similarity between two documents
@@ -47,13 +47,13 @@ export const calculateSemanticSimilarity = (
document1Embedding.length > 0 &&
document2Embedding.length > 0
) {
- const similarity = cosineSimilarity(document1Embedding, document2Embedding)
+ const similarity = cosineSimilarity(document1Embedding, document2Embedding);
// Convert from [-1, 1] to [0, 1] range
- return similarity >= 0 ? similarity : 0
+ return similarity >= 0 ? similarity : 0;
}
- return 0
-}
+ return 0;
+};
/**
* Calculate semantic similarity between a document and memory entry
@@ -71,34 +71,34 @@ export const calculateDocumentMemorySimilarity = (
documentEmbedding.length > 0 &&
memoryEmbedding.length > 0
) {
- const similarity = cosineSimilarity(documentEmbedding, memoryEmbedding)
+ const similarity = cosineSimilarity(documentEmbedding, memoryEmbedding);
// Convert from [-1, 1] to [0, 1] range
- return similarity >= 0 ? similarity : 0
+ return similarity >= 0 ? similarity : 0;
}
// Fall back to relevance score from database (0-100 scale)
if (relevanceScore !== null && relevanceScore !== undefined) {
- return Math.max(0, Math.min(1, relevanceScore / 100))
+ return Math.max(0, Math.min(1, relevanceScore / 100));
}
// Default similarity for connections without embeddings or relevance scores
- return 0.5
-}
+ return 0.5;
+};
/**
* Get visual properties for connection based on similarity
*/
export const getConnectionVisualProps = (similarity: number) => {
// Ensure similarity is between 0 and 1
- const normalizedSimilarity = Math.max(0, Math.min(1, similarity))
+ const normalizedSimilarity = Math.max(0, Math.min(1, similarity));
return {
opacity: Math.max(0, normalizedSimilarity), // 0 to 1 range
thickness: Math.max(1, normalizedSimilarity * 4), // 1 to 4 pixels
glow: normalizedSimilarity * 0.6, // Glow intensity
pulseDuration: 2000 + (1 - normalizedSimilarity) * 3000, // Faster pulse for higher similarity
- }
-}
+ };
+};
/**
* Generate magical color based on similarity and connection type
@@ -107,9 +107,9 @@ export const getMagicalConnectionColor = (
similarity: number,
hue = 220,
): string => {
- const normalizedSimilarity = Math.max(0, Math.min(1, similarity))
- const saturation = 60 + normalizedSimilarity * 40 // 60% to 100%
- const lightness = 40 + normalizedSimilarity * 30 // 40% to 70%
+ const normalizedSimilarity = Math.max(0, Math.min(1, similarity));
+ const saturation = 60 + normalizedSimilarity * 40; // 60% to 100%
+ const lightness = 40 + normalizedSimilarity * 30; // 40% to 70%
- return `hsl(${hue}, ${saturation}%, ${lightness}%)`
-}
+ return `hsl(${hue}, ${saturation}%, ${lightness}%)`;
+};
diff --git a/packages/lib/utils.ts b/packages/lib/utils.ts
index 02a2ddaf..59e86ae1 100644
--- a/packages/lib/utils.ts
+++ b/packages/lib/utils.ts
@@ -1,8 +1,8 @@
-import { type ClassValue, clsx } from "clsx"
-import { twMerge } from "tailwind-merge"
+import { type ClassValue, clsx } from "clsx";
+import { twMerge } from "tailwind-merge";
export function cn(...inputs: ClassValue[]) {
- return twMerge(clsx(inputs))
+ return twMerge(clsx(inputs));
}
-export const isSelfHosted = process.env.NEXT_PUBLIC_HOST_ID !== "supermemory"
+export const isSelfHosted = process.env.NEXT_PUBLIC_HOST_ID !== "supermemory";