From 004ac15cb365a8ecc14c270f3f9d5342d8886bc4 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Tue, 26 May 2026 23:08:57 +0000 Subject: [PATCH] fix(web): preserve remote resume edits during autosave --- apps/web/package.json | 1 + .../src/features/resume/builder/draft.test.ts | 143 ++++++++++++++---- apps/web/src/features/resume/builder/draft.ts | 129 +++++++++++++--- pnpm-lock.yaml | 59 ++++---- 4 files changed, 251 insertions(+), 81 deletions(-) diff --git a/apps/web/package.json b/apps/web/package.json index 0518e98ef..9adf6b256 100644 --- a/apps/web/package.json +++ b/apps/web/package.json @@ -40,6 +40,7 @@ "@reactive-resume/fonts": "workspace:*", "@reactive-resume/import": "workspace:*", "@reactive-resume/pdf": "workspace:*", + "@reactive-resume/resume": "workspace:*", "@reactive-resume/schema": "workspace:*", "@reactive-resume/ui": "workspace:*", "@reactive-resume/utils": "workspace:*", diff --git a/apps/web/src/features/resume/builder/draft.test.ts b/apps/web/src/features/resume/builder/draft.test.ts index 52a18142e..9cd8087c0 100644 --- a/apps/web/src/features/resume/builder/draft.test.ts +++ b/apps/web/src/features/resume/builder/draft.test.ts @@ -5,6 +5,7 @@ import type { Resume } from "./draft"; import { act, renderHook } from "@testing-library/react"; import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; import { i18n } from "@lingui/core"; +import { ORPCError } from "@orpc/client"; import { defaultResumeData } from "@reactive-resume/schema/resume/default"; import { useBuilderResumeUpdateSubscription, useResumeStore, useResumeUpdateSubscription } from "./draft"; @@ -30,9 +31,14 @@ const toastMocks = vi.hoisted(() => ({ error: vi.fn(() => "sync-error-toast"), })); -vi.mock("@orpc/client", () => ({ - consumeEventIterator: consumeEventIteratorMock, -})); +vi.mock("@orpc/client", async (importOriginal) => { + const actual = await importOriginal(); + + return { + ...actual, + consumeEventIterator: consumeEventIteratorMock, + }; +}); vi.mock("@tanstack/react-query", () => ({ useQueryClient: () => queryClientMock, @@ -103,10 +109,25 @@ function withBasicsName(resume: Resume, name: string): Resume { }; } +function withSummaryContent(resume: Resume, content: string): Resume { + return { + ...resume, + data: { + ...resume.data, + summary: { + ...resume.data.summary, + content, + }, + }, + }; +} + +function withUpdatedAt(resume: Resume, updatedAt: string): Resume { + return { ...resume, updatedAt: new Date(updatedAt) }; +} + async function flushMicrotasks() { - await Promise.resolve(); - await Promise.resolve(); - await Promise.resolve(); + for (let index = 0; index < 10; index += 1) await Promise.resolve(); } describe("builder resume autosave", () => { @@ -131,10 +152,11 @@ describe("builder resume autosave", () => { useResumeStore.getState().reset(); }); - it("coalesces rapid local edits into one full-data update", async () => { + it("coalesces rapid local edits into one data patch", async () => { const initial = makeResume("resume-rapid"); - const updated = withBasicsName(initial, "Latest Name"); + const updated = withUpdatedAt(withBasicsName(initial, "Latest Name"), "2026-05-26T12:01:00.000Z"); orpcMocks.updateResume.mockResolvedValue(updated); + orpcMocks.patchResume.mockResolvedValue(updated); useResumeStore.getState().initialize(initial); useResumeStore.getState().updateResumeData((draft) => { @@ -147,21 +169,25 @@ describe("builder resume autosave", () => { vi.advanceTimersByTime(500); await flushMicrotasks(); - expect(orpcMocks.updateResume).toHaveBeenCalledTimes(1); - expect(orpcMocks.updateResume).toHaveBeenCalledWith( - { id: initial.id, data: updated.data }, + expect(orpcMocks.patchResume).toHaveBeenCalledTimes(1); + expect(orpcMocks.patchResume).toHaveBeenCalledWith( + { + id: initial.id, + expectedUpdatedAt: initial.updatedAt, + operations: [{ op: "replace", path: "/basics/name", value: "Latest Name" }], + }, expect.objectContaining({ signal: expect.any(AbortSignal) }), ); - expect(orpcMocks.patchResume).not.toHaveBeenCalled(); + expect(orpcMocks.updateResume).not.toHaveBeenCalled(); }); it("saves the latest pending snapshot after an in-flight save resolves", async () => { const initial = makeResume("resume-in-flight"); - const first = withBasicsName(initial, "First Name"); - const latest = withBasicsName(initial, "Latest Name"); + const first = withUpdatedAt(withBasicsName(initial, "First Name"), "2026-05-26T12:01:00.000Z"); + const latest = withUpdatedAt(withBasicsName(initial, "Latest Name"), "2026-05-26T12:02:00.000Z"); let resolveFirst!: (resume: Resume) => void; - orpcMocks.updateResume + orpcMocks.patchResume .mockReturnValueOnce( new Promise((resolve) => { resolveFirst = resolve; @@ -183,24 +209,32 @@ describe("builder resume autosave", () => { vi.advanceTimersByTime(500); await flushMicrotasks(); - expect(orpcMocks.updateResume).toHaveBeenCalledTimes(1); + expect(orpcMocks.patchResume).toHaveBeenCalledTimes(1); resolveFirst(first); await flushMicrotasks(); - expect(orpcMocks.updateResume).toHaveBeenCalledTimes(2); - expect(orpcMocks.updateResume.mock.calls[0]?.[0]).toEqual({ id: initial.id, data: first.data }); - expect(orpcMocks.updateResume.mock.calls[1]?.[0]).toEqual({ id: initial.id, data: latest.data }); - expect(orpcMocks.patchResume).not.toHaveBeenCalled(); + expect(orpcMocks.patchResume).toHaveBeenCalledTimes(2); + expect(orpcMocks.patchResume.mock.calls[0]?.[0]).toEqual({ + id: initial.id, + expectedUpdatedAt: initial.updatedAt, + operations: [{ op: "replace", path: "/basics/name", value: "First Name" }], + }); + expect(orpcMocks.patchResume.mock.calls[1]?.[0]).toEqual({ + id: initial.id, + expectedUpdatedAt: first.updatedAt, + operations: [{ op: "replace", path: "/basics/name", value: "Latest Name" }], + }); + expect(orpcMocks.updateResume).not.toHaveBeenCalled(); }); it("does not run a stale debounced save after immediately saving an edit made during an in-flight save", async () => { const initial = makeResume("resume-stale-timer"); - const first = withBasicsName(initial, "First Name"); - const latest = withBasicsName(initial, "Latest Name"); + const first = withUpdatedAt(withBasicsName(initial, "First Name"), "2026-05-26T12:01:00.000Z"); + const latest = withUpdatedAt(withBasicsName(initial, "Latest Name"), "2026-05-26T12:02:00.000Z"); let resolveFirst!: (resume: Resume) => void; - orpcMocks.updateResume + orpcMocks.patchResume .mockReturnValueOnce( new Promise((resolve) => { resolveFirst = resolve; @@ -221,18 +255,22 @@ describe("builder resume autosave", () => { resolveFirst(first); await flushMicrotasks(); - expect(orpcMocks.updateResume).toHaveBeenCalledTimes(2); + expect(orpcMocks.patchResume).toHaveBeenCalledTimes(2); vi.advanceTimersByTime(500); await flushMicrotasks(); - expect(orpcMocks.updateResume).toHaveBeenCalledTimes(2); - expect(orpcMocks.updateResume.mock.calls[1]?.[0]).toEqual({ id: initial.id, data: latest.data }); + expect(orpcMocks.patchResume).toHaveBeenCalledTimes(2); + expect(orpcMocks.patchResume.mock.calls[1]?.[0]).toEqual({ + id: initial.id, + expectedUpdatedAt: first.updatedAt, + operations: [{ op: "replace", path: "/basics/name", value: "Latest Name" }], + }); }); it("keeps the latest draft data and shows a persistent toast when saving fails", async () => { const initial = makeResume("resume-failure"); - orpcMocks.updateResume.mockRejectedValue(new Error("network down")); + orpcMocks.patchResume.mockRejectedValue(new Error("network down")); useResumeStore.getState().initialize(initial); useResumeStore.getState().updateResumeData((draft) => { @@ -247,7 +285,42 @@ describe("builder resume autosave", () => { "Your latest changes could not be saved.", expect.objectContaining({ duration: Number.POSITIVE_INFINITY }), ); - expect(orpcMocks.patchResume).not.toHaveBeenCalled(); + expect(orpcMocks.updateResume).not.toHaveBeenCalled(); + }); + + it("rebases pending local edits after a server version conflict", async () => { + const initial = makeResume("resume-conflict"); + const remote = withUpdatedAt(withSummaryContent(initial, "Remote Summary"), "2026-05-26T12:01:00.000Z"); + const merged = withUpdatedAt(withBasicsName(remote, "Local Name"), "2026-05-26T12:02:00.000Z"); + + orpcMocks.patchResume.mockRejectedValueOnce(new ORPCError("RESUME_VERSION_CONFLICT")).mockResolvedValueOnce(merged); + orpcMocks.getResumeById.mockResolvedValue(remote); + useResumeStore.getState().initialize(initial); + + useResumeStore.getState().updateResumeData((draft) => { + draft.basics.name = "Local Name"; + }); + + vi.advanceTimersByTime(500); + await flushMicrotasks(); + + expect(orpcMocks.getResumeById).toHaveBeenCalledWith( + { id: initial.id }, + expect.objectContaining({ signal: expect.any(AbortSignal) }), + ); + expect(orpcMocks.patchResume).toHaveBeenCalledTimes(2); + expect(orpcMocks.patchResume.mock.calls[0]?.[0]).toEqual({ + id: initial.id, + expectedUpdatedAt: initial.updatedAt, + operations: [{ op: "replace", path: "/basics/name", value: "Local Name" }], + }); + expect(orpcMocks.patchResume.mock.calls[1]?.[0]).toEqual({ + id: initial.id, + expectedUpdatedAt: remote.updatedAt, + operations: [{ op: "replace", path: "/basics/name", value: "Local Name" }], + }); + expect(useResumeStore.getState().resume?.data.basics.name).toBe("Local Name"); + expect(useResumeStore.getState().resume?.data.summary.content).toBe("Remote Summary"); }); }); @@ -317,10 +390,12 @@ describe("resume update stream subscription", () => { it("does not overwrite pending local builder edits when a remote update arrives", async () => { const initial = makeResume("resume-pending"); - const remote = withBasicsName(initial, "Remote Name"); + const remote = withUpdatedAt(withSummaryContent(initial, "Remote Summary"), "2026-05-26T12:01:00.000Z"); + const merged = withUpdatedAt(withBasicsName(remote, "Local Name"), "2026-05-26T12:02:00.000Z"); const cancel = vi.fn().mockResolvedValue(undefined); consumeEventIteratorMock.mockReturnValue(cancel); orpcMocks.getResumeById.mockResolvedValue(remote); + orpcMocks.patchResume.mockResolvedValue(merged); routerParamsMock.value = { resumeId: initial.id }; useResumeStore.getState().initialize(initial); useResumeStore.getState().updateResumeData((draft) => { @@ -336,5 +411,15 @@ describe("resume update stream subscription", () => { expect(queryClientMock.setQueryData).toHaveBeenCalledWith(["resume", "getById", initial.id], remote); expect(useResumeStore.getState().resume?.data.basics.name).toBe("Local Name"); + expect(useResumeStore.getState().resume?.data.summary.content).toBe("Remote Summary"); + expect(orpcMocks.patchResume).toHaveBeenCalledWith( + { + id: initial.id, + expectedUpdatedAt: remote.updatedAt, + operations: [{ op: "replace", path: "/basics/name", value: "Local Name" }], + }, + expect.objectContaining({ signal: expect.any(AbortSignal) }), + ); + expect(orpcMocks.updateResume).not.toHaveBeenCalled(); }); }); diff --git a/apps/web/src/features/resume/builder/draft.ts b/apps/web/src/features/resume/builder/draft.ts index a0ef9b54d..139e177c4 100644 --- a/apps/web/src/features/resume/builder/draft.ts +++ b/apps/web/src/features/resume/builder/draft.ts @@ -2,7 +2,7 @@ import type { ResumeData } from "@reactive-resume/schema/resume/data"; import type { QueryClient, QueryKey } from "@tanstack/react-query"; import type { WritableDraft } from "immer"; import { t } from "@lingui/core/macro"; -import { consumeEventIterator } from "@orpc/client"; +import { consumeEventIterator, ORPCError } from "@orpc/client"; import { useQueryClient } from "@tanstack/react-query"; import { useParams } from "@tanstack/react-router"; import { debounce, isEqual } from "es-toolkit"; @@ -10,6 +10,7 @@ import { useCallback, useEffect, useState } from "react"; import { toast } from "sonner"; import { immer } from "zustand/middleware/immer"; import { create } from "zustand/react"; +import { applyResumePatches, createResumePatches } from "@reactive-resume/resume/patch"; import { orpc, streamClient } from "@/libs/orpc/client"; export type Resume = { @@ -48,6 +49,7 @@ type Runtime = { hasPendingLocalChanges: boolean; isSaving: boolean; pendingResume?: Resume; + serverResume?: Resume; syncErrorToastId?: string | number; syncResume: ReturnType void>>; beforeUnloadHandler?: () => void; @@ -82,57 +84,131 @@ function createResumeUpdateEventIterator(resumeId: string) { function setRuntimeBaseline(resume: Resume) { const runtime = getRuntime(resume.id); + runtime.serverResume = cloneResume(resume); runtime.hasPendingLocalChanges = false; runtime.pendingResume = undefined; } +function isAbortError(error: unknown): error is DOMException { + return error instanceof DOMException && error.name === "AbortError"; +} + +function isResumeVersionConflict(error: unknown): error is ORPCError { + return error instanceof ORPCError && error.code === "RESUME_VERSION_CONFLICT"; +} + +function rebasePendingResumeOnServer(serverResume: Resume, localResume: Resume) { + const runtime = getRuntime(serverResume.id); + const baseline = runtime.serverResume; + if (!baseline || baseline.id !== serverResume.id) { + throw new Error("Cannot rebase resume draft without a server baseline."); + } + + const operations = createResumePatches(baseline.data, localResume.data); + runtime.serverResume = cloneResume(serverResume); + runtime.queryClient?.setQueryData(getResumeQueryKey(serverResume.id), serverResume); + + if (operations.length === 0) { + runtime.hasPendingLocalChanges = false; + runtime.pendingResume = undefined; + useResumeStore.getState().replaceResumeFromServer(serverResume); + return; + } + + const rebased: Resume = { + ...serverResume, + data: applyResumePatches(serverResume.data, operations), + }; + + runtime.syncResume.cancel(); + runtime.pendingResume = cloneResume(rebased); + runtime.hasPendingLocalChanges = true; + useResumeStore.getState().replaceResumeDraft(rebased); +} + +function handleSuccessfulResumeSave(runtime: Runtime, submitted: Resume, saved: Resume, submittedData: ResumeData) { + runtime.serverResume = cloneResume(saved); + runtime.queryClient?.setQueryData(getResumeQueryKey(submitted.id), saved); + + const currentResume = useResumeStore.getState().resume; + const currentDataStillMatchesSubmission = + currentResume?.id === submitted.id && isEqual(currentResume.data, submittedData); + + if (currentDataStillMatchesSubmission && !runtime.pendingResume) { + runtime.hasPendingLocalChanges = false; + useResumeStore.getState().replaceResumeFromServer(saved); + } else { + runtime.hasPendingLocalChanges = true; + useResumeStore.getState().mergeResumeMetadata(saved); + + if (!runtime.pendingResume && currentResume?.id === submitted.id && !isEqual(currentResume.data, submittedData)) { + runtime.syncResume.cancel(); + runtime.pendingResume = cloneResume(currentResume); + } + } + + if (runtime.syncErrorToastId !== undefined) { + toast.dismiss(runtime.syncErrorToastId); + runtime.syncErrorToastId = undefined; + } +} + async function flushResumeSave(id: string) { const runtime = runtimes.get(id); if (!runtime || runtime.isSaving || !runtime.pendingResume) return; const submitted = runtime.pendingResume; const submittedData = cloneResumeData(submitted.data); + const baseline = runtime.serverResume; runtime.pendingResume = undefined; runtime.isSaving = true; try { - const updated = (await orpc.resume.update.call( - { id: submitted.id, data: submittedData }, + if (!baseline || baseline.id !== submitted.id) { + throw new Error("Cannot save resume draft without a server baseline."); + } + + const operations = createResumePatches(baseline.data, submittedData); + if (operations.length === 0) { + handleSuccessfulResumeSave(runtime, submitted, baseline, submittedData); + return; + } + + const updated = (await orpc.resume.patch.call( + { id: submitted.id, expectedUpdatedAt: baseline.updatedAt, operations }, { signal: runtime.abortController.signal }, )) as Resume; - runtime.queryClient?.setQueryData(getResumeQueryKey(submitted.id), updated); + handleSuccessfulResumeSave(runtime, submitted, updated, submittedData); + } catch (error: unknown) { + if (isAbortError(error)) return; - const currentResume = useResumeStore.getState().resume; - const currentDataStillMatchesSubmission = - currentResume?.id === submitted.id && isEqual(currentResume.data, submittedData); + let syncError = error; - if (currentDataStillMatchesSubmission && !runtime.pendingResume) { - runtime.hasPendingLocalChanges = false; - useResumeStore.getState().replaceResumeFromServer(updated); - } else { - runtime.hasPendingLocalChanges = true; - useResumeStore.getState().mergeResumeMetadata(updated); + if (isResumeVersionConflict(error)) { + try { + const latest = (await orpc.resume.getById.call( + { id: submitted.id }, + { signal: runtime.abortController.signal }, + )) as Resume; + const currentResume = useResumeStore.getState().resume; + const localResume = currentResume?.id === submitted.id ? currentResume : submitted; - if (!runtime.pendingResume && currentResume?.id === submitted.id && !isEqual(currentResume.data, submittedData)) { - runtime.syncResume.cancel(); - runtime.pendingResume = cloneResume(currentResume); + rebasePendingResumeOnServer(latest, localResume); + return; + } catch (rebaseError: unknown) { + if (isAbortError(rebaseError)) return; + syncError = rebaseError; } } - if (runtime.syncErrorToastId !== undefined) { - toast.dismiss(runtime.syncErrorToastId); - runtime.syncErrorToastId = undefined; - } - } catch (error: unknown) { - if (error instanceof DOMException && error.name === "AbortError") return; - runtime.pendingResume ??= submitted; runtime.hasPendingLocalChanges = true; runtime.syncErrorToastId = toast.error(t`Your latest changes could not be saved.`, { id: runtime.syncErrorToastId, duration: Number.POSITIVE_INFINITY, }); + console.warn("Resume autosave failed:", syncError); } finally { runtime.isSaving = false; if (runtime.pendingResume && runtime.syncErrorToastId === undefined) void flushResumeSave(id); @@ -404,7 +480,12 @@ export function useBuilderResumeUpdateSubscription() { queryClient.setQueryData(getResumeQueryKey(resumeId), resume); if (hasPendingLocalChanges(resumeId)) { - useResumeStore.getState().mergeResumeMetadata(resume); + const currentResume = useResumeStore.getState().resume; + if (!currentResume || currentResume.id !== resumeId) return; + + rebasePendingResumeOnServer(resume, currentResume); + const runtime = getRuntime(resumeId); + if (!runtime.isSaving && runtime.syncErrorToastId === undefined) void flushResumeSave(resumeId); return; } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index a59ad6d51..c0abc9170 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -85,19 +85,19 @@ importers: version: 3.1053.0 '@better-auth/api-key': specifier: ^1.6.11 - version: 1.6.11(@better-auth/core@1.6.11(@better-auth/utils@0.4.0)(@better-fetch/fetch@1.1.21)(@opentelemetry/api@1.9.1)(better-call@1.3.5(zod@4.4.3))(jose@6.2.3)(kysely@0.28.17)(nanostores@1.3.0))(@better-auth/utils@0.4.0)(better-auth@1.6.11(@opentelemetry/api@1.9.1)(drizzle-orm@1.0.0-rc.3(@opentelemetry/api@1.9.1)(@types/pg@8.20.0)(effect@4.0.0-beta.70)(pg@8.21.0)(zod@4.4.3))(next@16.2.6(@babel/core@7.29.7)(@opentelemetry/api@1.9.1)(babel-plugin-macros@3.1.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(pg@8.21.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(vitest@4.1.7)) + version: 1.6.11(@better-auth/core@1.6.11(@better-auth/utils@0.4.0)(@better-fetch/fetch@1.1.21)(@opentelemetry/api@1.9.1)(better-call@1.3.5(zod@4.4.3))(jose@6.2.3)(kysely@0.28.17)(nanostores@1.3.0))(@better-auth/utils@0.4.0)(better-auth@1.6.11(@opentelemetry/api@1.9.1)(drizzle-orm@1.0.0-rc.3(@opentelemetry/api@1.9.1)(@types/pg@8.20.0)(effect@4.0.0-beta.70)(pg@8.21.0)(zod@4.4.3))(next@16.2.6(@opentelemetry/api@1.9.1)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(pg@8.21.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(vitest@4.1.7)) '@better-auth/drizzle-adapter': specifier: ^1.6.11 version: 1.6.11(@better-auth/core@1.6.11(@better-auth/utils@0.4.0)(@better-fetch/fetch@1.1.21)(@opentelemetry/api@1.9.1)(better-call@1.3.5(zod@4.4.3))(jose@6.2.3)(kysely@0.28.17)(nanostores@1.3.0))(@better-auth/utils@0.4.0)(drizzle-orm@1.0.0-rc.3(@opentelemetry/api@1.9.1)(@types/pg@8.20.0)(effect@4.0.0-beta.70)(pg@8.21.0)(zod@4.4.3)) '@better-auth/infra': specifier: ^0.2.8 - version: 0.2.8(97af957868093b766f74c847443b5514) + version: 0.2.8(52486eeb3cc3b91786b2cceb6f087465) '@better-auth/oauth-provider': specifier: ^1.6.11 - version: 1.6.11(@better-auth/core@1.6.11(@better-auth/utils@0.4.0)(@better-fetch/fetch@1.1.21)(@opentelemetry/api@1.9.1)(better-call@1.3.5(zod@4.4.3))(jose@6.2.3)(kysely@0.28.17)(nanostores@1.3.0))(@better-auth/utils@0.4.0)(@better-fetch/fetch@1.1.21)(better-auth@1.6.11(@opentelemetry/api@1.9.1)(drizzle-orm@1.0.0-rc.3(@opentelemetry/api@1.9.1)(@types/pg@8.20.0)(effect@4.0.0-beta.70)(pg@8.21.0)(zod@4.4.3))(next@16.2.6(@babel/core@7.29.7)(@opentelemetry/api@1.9.1)(babel-plugin-macros@3.1.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(pg@8.21.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(vitest@4.1.7))(better-call@1.3.5(zod@4.4.3)) + version: 1.6.11(@better-auth/core@1.6.11(@better-auth/utils@0.4.0)(@better-fetch/fetch@1.1.21)(@opentelemetry/api@1.9.1)(better-call@1.3.5(zod@4.4.3))(jose@6.2.3)(kysely@0.28.17)(nanostores@1.3.0))(@better-auth/utils@0.4.0)(@better-fetch/fetch@1.1.21)(better-auth@1.6.11(@opentelemetry/api@1.9.1)(drizzle-orm@1.0.0-rc.3(@opentelemetry/api@1.9.1)(@types/pg@8.20.0)(effect@4.0.0-beta.70)(pg@8.21.0)(zod@4.4.3))(next@16.2.6(@opentelemetry/api@1.9.1)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(pg@8.21.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(vitest@4.1.7))(better-call@1.3.5(zod@4.4.3)) '@better-auth/passkey': specifier: ^1.6.11 - version: 1.6.11(@better-auth/core@1.6.11(@better-auth/utils@0.4.0)(@better-fetch/fetch@1.1.21)(@opentelemetry/api@1.9.1)(better-call@1.3.5(zod@4.4.3))(jose@6.2.3)(kysely@0.28.17)(nanostores@1.3.0))(@better-auth/utils@0.4.0)(@better-fetch/fetch@1.1.21)(better-auth@1.6.11(@opentelemetry/api@1.9.1)(drizzle-orm@1.0.0-rc.3(@opentelemetry/api@1.9.1)(@types/pg@8.20.0)(effect@4.0.0-beta.70)(pg@8.21.0)(zod@4.4.3))(next@16.2.6(@babel/core@7.29.7)(@opentelemetry/api@1.9.1)(babel-plugin-macros@3.1.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(pg@8.21.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(vitest@4.1.7))(better-call@1.3.5(zod@4.4.3))(nanostores@1.3.0) + version: 1.6.11(@better-auth/core@1.6.11(@better-auth/utils@0.4.0)(@better-fetch/fetch@1.1.21)(@opentelemetry/api@1.9.1)(better-call@1.3.5(zod@4.4.3))(jose@6.2.3)(kysely@0.28.17)(nanostores@1.3.0))(@better-auth/utils@0.4.0)(@better-fetch/fetch@1.1.21)(better-auth@1.6.11(@opentelemetry/api@1.9.1)(drizzle-orm@1.0.0-rc.3(@opentelemetry/api@1.9.1)(@types/pg@8.20.0)(effect@4.0.0-beta.70)(pg@8.21.0)(zod@4.4.3))(next@16.2.6(@opentelemetry/api@1.9.1)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(pg@8.21.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(vitest@4.1.7))(better-call@1.3.5(zod@4.4.3))(nanostores@1.3.0) '@hono/node-server': specifier: ^2.0.4 version: 2.0.4(hono@4.12.23) @@ -163,7 +163,7 @@ importers: version: 6.0.0 better-auth: specifier: 1.6.11 - version: 1.6.11(@opentelemetry/api@1.9.1)(drizzle-orm@1.0.0-rc.3(@opentelemetry/api@1.9.1)(@types/pg@8.20.0)(effect@4.0.0-beta.70)(pg@8.21.0)(zod@4.4.3))(next@16.2.6(@babel/core@7.29.7)(@opentelemetry/api@1.9.1)(babel-plugin-macros@3.1.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(pg@8.21.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(vitest@4.1.7) + version: 1.6.11(@opentelemetry/api@1.9.1)(drizzle-orm@1.0.0-rc.3(@opentelemetry/api@1.9.1)(@types/pg@8.20.0)(effect@4.0.0-beta.70)(pg@8.21.0)(zod@4.4.3))(next@16.2.6(@opentelemetry/api@1.9.1)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(pg@8.21.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(vitest@4.1.7) cjk-regex: specifier: ^3.4.0 version: 3.4.0 @@ -278,16 +278,16 @@ importers: version: 1.5.0(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) '@better-auth/api-key': specifier: ^1.6.11 - version: 1.6.11(@better-auth/core@1.6.11(@better-auth/utils@0.4.0)(@better-fetch/fetch@1.1.21)(@opentelemetry/api@1.9.1)(better-call@1.3.5(zod@4.4.3))(jose@6.2.3)(kysely@0.28.17)(nanostores@1.3.0))(@better-auth/utils@0.4.0)(better-auth@1.6.11(@opentelemetry/api@1.9.1)(drizzle-orm@1.0.0-rc.3(@opentelemetry/api@1.9.1)(@types/pg@8.20.0)(effect@4.0.0-beta.70)(pg@8.21.0)(zod@4.4.3))(next@16.2.6(@babel/core@7.29.7)(@opentelemetry/api@1.9.1)(babel-plugin-macros@3.1.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(pg@8.21.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(vitest@4.1.7)) + version: 1.6.11(@better-auth/core@1.6.11(@better-auth/utils@0.4.0)(@better-fetch/fetch@1.1.21)(@opentelemetry/api@1.9.1)(better-call@1.3.5(zod@4.4.3))(jose@6.2.3)(kysely@0.28.17)(nanostores@1.3.0))(@better-auth/utils@0.4.0)(better-auth@1.6.11(@opentelemetry/api@1.9.1)(drizzle-orm@1.0.0-rc.3(@opentelemetry/api@1.9.1)(@types/pg@8.20.0)(effect@4.0.0-beta.70)(pg@8.21.0)(zod@4.4.3))(next@16.2.6(@opentelemetry/api@1.9.1)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(pg@8.21.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(vitest@4.1.7)) '@better-auth/infra': specifier: ^0.2.8 - version: 0.2.8(97af957868093b766f74c847443b5514) + version: 0.2.8(52486eeb3cc3b91786b2cceb6f087465) '@better-auth/oauth-provider': specifier: ^1.6.11 - version: 1.6.11(@better-auth/core@1.6.11(@better-auth/utils@0.4.0)(@better-fetch/fetch@1.1.21)(@opentelemetry/api@1.9.1)(better-call@1.3.5(zod@4.4.3))(jose@6.2.3)(kysely@0.28.17)(nanostores@1.3.0))(@better-auth/utils@0.4.0)(@better-fetch/fetch@1.1.21)(better-auth@1.6.11(@opentelemetry/api@1.9.1)(drizzle-orm@1.0.0-rc.3(@opentelemetry/api@1.9.1)(@types/pg@8.20.0)(effect@4.0.0-beta.70)(pg@8.21.0)(zod@4.4.3))(next@16.2.6(@babel/core@7.29.7)(@opentelemetry/api@1.9.1)(babel-plugin-macros@3.1.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(pg@8.21.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(vitest@4.1.7))(better-call@1.3.5(zod@4.4.3)) + version: 1.6.11(@better-auth/core@1.6.11(@better-auth/utils@0.4.0)(@better-fetch/fetch@1.1.21)(@opentelemetry/api@1.9.1)(better-call@1.3.5(zod@4.4.3))(jose@6.2.3)(kysely@0.28.17)(nanostores@1.3.0))(@better-auth/utils@0.4.0)(@better-fetch/fetch@1.1.21)(better-auth@1.6.11(@opentelemetry/api@1.9.1)(drizzle-orm@1.0.0-rc.3(@opentelemetry/api@1.9.1)(@types/pg@8.20.0)(effect@4.0.0-beta.70)(pg@8.21.0)(zod@4.4.3))(next@16.2.6(@opentelemetry/api@1.9.1)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(pg@8.21.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(vitest@4.1.7))(better-call@1.3.5(zod@4.4.3)) '@better-auth/passkey': specifier: ^1.6.11 - version: 1.6.11(@better-auth/core@1.6.11(@better-auth/utils@0.4.0)(@better-fetch/fetch@1.1.21)(@opentelemetry/api@1.9.1)(better-call@1.3.5(zod@4.4.3))(jose@6.2.3)(kysely@0.28.17)(nanostores@1.3.0))(@better-auth/utils@0.4.0)(@better-fetch/fetch@1.1.21)(better-auth@1.6.11(@opentelemetry/api@1.9.1)(drizzle-orm@1.0.0-rc.3(@opentelemetry/api@1.9.1)(@types/pg@8.20.0)(effect@4.0.0-beta.70)(pg@8.21.0)(zod@4.4.3))(next@16.2.6(@babel/core@7.29.7)(@opentelemetry/api@1.9.1)(babel-plugin-macros@3.1.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(pg@8.21.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(vitest@4.1.7))(better-call@1.3.5(zod@4.4.3))(nanostores@1.3.0) + version: 1.6.11(@better-auth/core@1.6.11(@better-auth/utils@0.4.0)(@better-fetch/fetch@1.1.21)(@opentelemetry/api@1.9.1)(better-call@1.3.5(zod@4.4.3))(jose@6.2.3)(kysely@0.28.17)(nanostores@1.3.0))(@better-auth/utils@0.4.0)(@better-fetch/fetch@1.1.21)(better-auth@1.6.11(@opentelemetry/api@1.9.1)(drizzle-orm@1.0.0-rc.3(@opentelemetry/api@1.9.1)(@types/pg@8.20.0)(effect@4.0.0-beta.70)(pg@8.21.0)(zod@4.4.3))(next@16.2.6(@opentelemetry/api@1.9.1)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(pg@8.21.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(vitest@4.1.7))(better-call@1.3.5(zod@4.4.3))(nanostores@1.3.0) '@dnd-kit/core': specifier: ^6.3.1 version: 6.3.1(react-dom@19.2.6(react@19.2.6))(react@19.2.6) @@ -339,6 +339,9 @@ importers: '@reactive-resume/pdf': specifier: workspace:* version: link:../../packages/pdf + '@reactive-resume/resume': + specifier: workspace:* + version: link:../../packages/resume '@reactive-resume/schema': specifier: workspace:* version: link:../../packages/schema @@ -401,7 +404,7 @@ importers: version: 6.0.191(zod@4.4.3) better-auth: specifier: 1.6.11 - version: 1.6.11(@opentelemetry/api@1.9.1)(drizzle-orm@1.0.0-rc.3(@opentelemetry/api@1.9.1)(@types/pg@8.20.0)(effect@4.0.0-beta.70)(pg@8.21.0)(zod@4.4.3))(next@16.2.6(@babel/core@7.29.7)(@opentelemetry/api@1.9.1)(babel-plugin-macros@3.1.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(pg@8.21.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(vitest@4.1.7) + version: 1.6.11(@opentelemetry/api@1.9.1)(drizzle-orm@1.0.0-rc.3(@opentelemetry/api@1.9.1)(@types/pg@8.20.0)(effect@4.0.0-beta.70)(pg@8.21.0)(zod@4.4.3))(next@16.2.6(@opentelemetry/api@1.9.1)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(pg@8.21.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(vitest@4.1.7) cmdk: specifier: ^1.1.1 version: 1.1.1(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) @@ -613,7 +616,7 @@ importers: version: 6.0.0 better-auth: specifier: 1.6.11 - version: 1.6.11(@opentelemetry/api@1.9.1)(drizzle-orm@1.0.0-rc.3(@opentelemetry/api@1.9.1)(@types/pg@8.20.0)(effect@4.0.0-beta.70)(pg@8.21.0)(zod@4.4.3))(next@16.2.6(@babel/core@7.29.7)(@opentelemetry/api@1.9.1)(babel-plugin-macros@3.1.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(pg@8.21.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(vitest@4.1.7) + version: 1.6.11(@opentelemetry/api@1.9.1)(drizzle-orm@1.0.0-rc.3(@opentelemetry/api@1.9.1)(@types/pg@8.20.0)(effect@4.0.0-beta.70)(pg@8.21.0)(zod@4.4.3))(next@16.2.6(@opentelemetry/api@1.9.1)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(pg@8.21.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(vitest@4.1.7) drizzle-orm: specifier: 1.0.0-rc.3 version: 1.0.0-rc.3(@opentelemetry/api@1.9.1)(@types/pg@8.20.0)(effect@4.0.0-beta.70)(pg@8.21.0)(zod@4.4.3) @@ -662,19 +665,19 @@ importers: dependencies: '@better-auth/api-key': specifier: ^1.6.11 - version: 1.6.11(@better-auth/core@1.6.11(@better-auth/utils@0.4.0)(@better-fetch/fetch@1.1.21)(@opentelemetry/api@1.9.1)(better-call@1.3.5(zod@4.4.3))(jose@6.2.3)(kysely@0.28.17)(nanostores@1.3.0))(@better-auth/utils@0.4.0)(better-auth@1.6.11(@opentelemetry/api@1.9.1)(drizzle-orm@1.0.0-rc.3(@opentelemetry/api@1.9.1)(@types/pg@8.20.0)(effect@4.0.0-beta.70)(pg@8.21.0)(zod@4.4.3))(next@16.2.6(@babel/core@7.29.7)(@opentelemetry/api@1.9.1)(babel-plugin-macros@3.1.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(pg@8.21.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(vitest@4.1.7)) + version: 1.6.11(@better-auth/core@1.6.11(@better-auth/utils@0.4.0)(@better-fetch/fetch@1.1.21)(@opentelemetry/api@1.9.1)(better-call@1.3.5(zod@4.4.3))(jose@6.2.3)(kysely@0.28.17)(nanostores@1.3.0))(@better-auth/utils@0.4.0)(better-auth@1.6.11(@opentelemetry/api@1.9.1)(drizzle-orm@1.0.0-rc.3(@opentelemetry/api@1.9.1)(@types/pg@8.20.0)(effect@4.0.0-beta.70)(pg@8.21.0)(zod@4.4.3))(next@16.2.6(@opentelemetry/api@1.9.1)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(pg@8.21.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(vitest@4.1.7)) '@better-auth/drizzle-adapter': specifier: ^1.6.11 version: 1.6.11(@better-auth/core@1.6.11(@better-auth/utils@0.4.0)(@better-fetch/fetch@1.1.21)(@opentelemetry/api@1.9.1)(better-call@1.3.5(zod@4.4.3))(jose@6.2.3)(kysely@0.28.17)(nanostores@1.3.0))(@better-auth/utils@0.4.0)(drizzle-orm@1.0.0-rc.3(@opentelemetry/api@1.9.1)(@types/pg@8.20.0)(effect@4.0.0-beta.70)(pg@8.21.0)(zod@4.4.3)) '@better-auth/infra': specifier: ^0.2.8 - version: 0.2.8(97af957868093b766f74c847443b5514) + version: 0.2.8(52486eeb3cc3b91786b2cceb6f087465) '@better-auth/oauth-provider': specifier: ^1.6.11 - version: 1.6.11(@better-auth/core@1.6.11(@better-auth/utils@0.4.0)(@better-fetch/fetch@1.1.21)(@opentelemetry/api@1.9.1)(better-call@1.3.5(zod@4.4.3))(jose@6.2.3)(kysely@0.28.17)(nanostores@1.3.0))(@better-auth/utils@0.4.0)(@better-fetch/fetch@1.1.21)(better-auth@1.6.11(@opentelemetry/api@1.9.1)(drizzle-orm@1.0.0-rc.3(@opentelemetry/api@1.9.1)(@types/pg@8.20.0)(effect@4.0.0-beta.70)(pg@8.21.0)(zod@4.4.3))(next@16.2.6(@babel/core@7.29.7)(@opentelemetry/api@1.9.1)(babel-plugin-macros@3.1.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(pg@8.21.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(vitest@4.1.7))(better-call@1.3.5(zod@4.4.3)) + version: 1.6.11(@better-auth/core@1.6.11(@better-auth/utils@0.4.0)(@better-fetch/fetch@1.1.21)(@opentelemetry/api@1.9.1)(better-call@1.3.5(zod@4.4.3))(jose@6.2.3)(kysely@0.28.17)(nanostores@1.3.0))(@better-auth/utils@0.4.0)(@better-fetch/fetch@1.1.21)(better-auth@1.6.11(@opentelemetry/api@1.9.1)(drizzle-orm@1.0.0-rc.3(@opentelemetry/api@1.9.1)(@types/pg@8.20.0)(effect@4.0.0-beta.70)(pg@8.21.0)(zod@4.4.3))(next@16.2.6(@opentelemetry/api@1.9.1)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(pg@8.21.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(vitest@4.1.7))(better-call@1.3.5(zod@4.4.3)) '@better-auth/passkey': specifier: ^1.6.11 - version: 1.6.11(@better-auth/core@1.6.11(@better-auth/utils@0.4.0)(@better-fetch/fetch@1.1.21)(@opentelemetry/api@1.9.1)(better-call@1.3.5(zod@4.4.3))(jose@6.2.3)(kysely@0.28.17)(nanostores@1.3.0))(@better-auth/utils@0.4.0)(@better-fetch/fetch@1.1.21)(better-auth@1.6.11(@opentelemetry/api@1.9.1)(drizzle-orm@1.0.0-rc.3(@opentelemetry/api@1.9.1)(@types/pg@8.20.0)(effect@4.0.0-beta.70)(pg@8.21.0)(zod@4.4.3))(next@16.2.6(@babel/core@7.29.7)(@opentelemetry/api@1.9.1)(babel-plugin-macros@3.1.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(pg@8.21.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(vitest@4.1.7))(better-call@1.3.5(zod@4.4.3))(nanostores@1.3.0) + version: 1.6.11(@better-auth/core@1.6.11(@better-auth/utils@0.4.0)(@better-fetch/fetch@1.1.21)(@opentelemetry/api@1.9.1)(better-call@1.3.5(zod@4.4.3))(jose@6.2.3)(kysely@0.28.17)(nanostores@1.3.0))(@better-auth/utils@0.4.0)(@better-fetch/fetch@1.1.21)(better-auth@1.6.11(@opentelemetry/api@1.9.1)(drizzle-orm@1.0.0-rc.3(@opentelemetry/api@1.9.1)(@types/pg@8.20.0)(effect@4.0.0-beta.70)(pg@8.21.0)(zod@4.4.3))(next@16.2.6(@opentelemetry/api@1.9.1)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(pg@8.21.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(vitest@4.1.7))(better-call@1.3.5(zod@4.4.3))(nanostores@1.3.0) '@reactive-resume/db': specifier: workspace:* version: link:../db @@ -692,7 +695,7 @@ importers: version: 6.0.0 better-auth: specifier: 1.6.11 - version: 1.6.11(@opentelemetry/api@1.9.1)(drizzle-orm@1.0.0-rc.3(@opentelemetry/api@1.9.1)(@types/pg@8.20.0)(effect@4.0.0-beta.70)(pg@8.21.0)(zod@4.4.3))(next@16.2.6(@babel/core@7.29.7)(@opentelemetry/api@1.9.1)(babel-plugin-macros@3.1.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(pg@8.21.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(vitest@4.1.7) + version: 1.6.11(@opentelemetry/api@1.9.1)(drizzle-orm@1.0.0-rc.3(@opentelemetry/api@1.9.1)(@types/pg@8.20.0)(effect@4.0.0-beta.70)(pg@8.21.0)(zod@4.4.3))(next@16.2.6(@opentelemetry/api@1.9.1)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(pg@8.21.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(vitest@4.1.7) drizzle-orm: specifier: 1.0.0-rc.3 version: 1.0.0-rc.3(@opentelemetry/api@1.9.1)(@types/pg@8.20.0)(effect@4.0.0-beta.70)(pg@8.21.0)(zod@4.4.3) @@ -8621,11 +8624,11 @@ snapshots: '@bcoe/v8-coverage@1.0.2': {} - '@better-auth/api-key@1.6.11(@better-auth/core@1.6.11(@better-auth/utils@0.4.0)(@better-fetch/fetch@1.1.21)(@opentelemetry/api@1.9.1)(better-call@1.3.5(zod@4.4.3))(jose@6.2.3)(kysely@0.28.17)(nanostores@1.3.0))(@better-auth/utils@0.4.0)(better-auth@1.6.11(@opentelemetry/api@1.9.1)(drizzle-orm@1.0.0-rc.3(@opentelemetry/api@1.9.1)(@types/pg@8.20.0)(effect@4.0.0-beta.70)(pg@8.21.0)(zod@4.4.3))(next@16.2.6(@babel/core@7.29.7)(@opentelemetry/api@1.9.1)(babel-plugin-macros@3.1.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(pg@8.21.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(vitest@4.1.7))': + '@better-auth/api-key@1.6.11(@better-auth/core@1.6.11(@better-auth/utils@0.4.0)(@better-fetch/fetch@1.1.21)(@opentelemetry/api@1.9.1)(better-call@1.3.5(zod@4.4.3))(jose@6.2.3)(kysely@0.28.17)(nanostores@1.3.0))(@better-auth/utils@0.4.0)(better-auth@1.6.11(@opentelemetry/api@1.9.1)(drizzle-orm@1.0.0-rc.3(@opentelemetry/api@1.9.1)(@types/pg@8.20.0)(effect@4.0.0-beta.70)(pg@8.21.0)(zod@4.4.3))(next@16.2.6(@opentelemetry/api@1.9.1)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(pg@8.21.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(vitest@4.1.7))': dependencies: '@better-auth/core': 1.6.11(@better-auth/utils@0.4.0)(@better-fetch/fetch@1.1.21)(@opentelemetry/api@1.9.1)(better-call@1.3.5(zod@4.4.3))(jose@6.2.3)(kysely@0.28.17)(nanostores@1.3.0) '@better-auth/utils': 0.4.0 - better-auth: 1.6.11(@opentelemetry/api@1.9.1)(drizzle-orm@1.0.0-rc.3(@opentelemetry/api@1.9.1)(@types/pg@8.20.0)(effect@4.0.0-beta.70)(pg@8.21.0)(zod@4.4.3))(next@16.2.6(@babel/core@7.29.7)(@opentelemetry/api@1.9.1)(babel-plugin-macros@3.1.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(pg@8.21.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(vitest@4.1.7) + better-auth: 1.6.11(@opentelemetry/api@1.9.1)(drizzle-orm@1.0.0-rc.3(@opentelemetry/api@1.9.1)(@types/pg@8.20.0)(effect@4.0.0-beta.70)(pg@8.21.0)(zod@4.4.3))(next@16.2.6(@opentelemetry/api@1.9.1)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(pg@8.21.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(vitest@4.1.7) zod: 4.4.3 '@better-auth/core@1.6.11(@better-auth/utils@0.4.0)(@better-fetch/fetch@1.1.21)(@opentelemetry/api@1.9.1)(better-call@1.3.5(zod@4.4.3))(jose@6.2.3)(kysely@0.28.17)(nanostores@1.3.0)': @@ -8649,12 +8652,12 @@ snapshots: optionalDependencies: drizzle-orm: 1.0.0-rc.3(@opentelemetry/api@1.9.1)(@types/pg@8.20.0)(effect@4.0.0-beta.70)(pg@8.21.0)(zod@4.4.3) - '@better-auth/infra@0.2.8(97af957868093b766f74c847443b5514)': + '@better-auth/infra@0.2.8(52486eeb3cc3b91786b2cceb6f087465)': dependencies: '@better-auth/core': 1.6.11(@better-auth/utils@0.4.0)(@better-fetch/fetch@1.1.21)(@opentelemetry/api@1.9.1)(better-call@1.3.5(zod@4.4.3))(jose@6.2.3)(kysely@0.28.17)(nanostores@1.3.0) - '@better-auth/sso': 1.6.11(@better-auth/core@1.6.11(@better-auth/utils@0.4.0)(@better-fetch/fetch@1.1.21)(@opentelemetry/api@1.9.1)(better-call@1.3.5(zod@4.4.3))(jose@6.2.3)(kysely@0.28.17)(nanostores@1.3.0))(@better-auth/utils@0.4.0)(@better-fetch/fetch@1.1.21)(better-auth@1.6.11(@opentelemetry/api@1.9.1)(drizzle-orm@1.0.0-rc.3(@opentelemetry/api@1.9.1)(@types/pg@8.20.0)(effect@4.0.0-beta.70)(pg@8.21.0)(zod@4.4.3))(next@16.2.6(@babel/core@7.29.7)(@opentelemetry/api@1.9.1)(babel-plugin-macros@3.1.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(pg@8.21.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(vitest@4.1.7))(better-call@1.3.5(zod@4.4.3)) + '@better-auth/sso': 1.6.11(@better-auth/core@1.6.11(@better-auth/utils@0.4.0)(@better-fetch/fetch@1.1.21)(@opentelemetry/api@1.9.1)(better-call@1.3.5(zod@4.4.3))(jose@6.2.3)(kysely@0.28.17)(nanostores@1.3.0))(@better-auth/utils@0.4.0)(@better-fetch/fetch@1.1.21)(better-auth@1.6.11(@opentelemetry/api@1.9.1)(drizzle-orm@1.0.0-rc.3(@opentelemetry/api@1.9.1)(@types/pg@8.20.0)(effect@4.0.0-beta.70)(pg@8.21.0)(zod@4.4.3))(next@16.2.6(@opentelemetry/api@1.9.1)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(pg@8.21.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(vitest@4.1.7))(better-call@1.3.5(zod@4.4.3)) '@better-fetch/fetch': 1.1.21 - better-auth: 1.6.11(@opentelemetry/api@1.9.1)(drizzle-orm@1.0.0-rc.3(@opentelemetry/api@1.9.1)(@types/pg@8.20.0)(effect@4.0.0-beta.70)(pg@8.21.0)(zod@4.4.3))(next@16.2.6(@babel/core@7.29.7)(@opentelemetry/api@1.9.1)(babel-plugin-macros@3.1.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(pg@8.21.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(vitest@4.1.7) + better-auth: 1.6.11(@opentelemetry/api@1.9.1)(drizzle-orm@1.0.0-rc.3(@opentelemetry/api@1.9.1)(@types/pg@8.20.0)(effect@4.0.0-beta.70)(pg@8.21.0)(zod@4.4.3))(next@16.2.6(@opentelemetry/api@1.9.1)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(pg@8.21.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(vitest@4.1.7) better-call: 1.3.5(zod@4.4.3) jose: 6.2.3 libphonenumber-js: 1.13.3 @@ -8677,24 +8680,24 @@ snapshots: '@better-auth/core': 1.6.11(@better-auth/utils@0.4.0)(@better-fetch/fetch@1.1.21)(@opentelemetry/api@1.9.1)(better-call@1.3.5(zod@4.4.3))(jose@6.2.3)(kysely@0.28.17)(nanostores@1.3.0) '@better-auth/utils': 0.4.0 - '@better-auth/oauth-provider@1.6.11(@better-auth/core@1.6.11(@better-auth/utils@0.4.0)(@better-fetch/fetch@1.1.21)(@opentelemetry/api@1.9.1)(better-call@1.3.5(zod@4.4.3))(jose@6.2.3)(kysely@0.28.17)(nanostores@1.3.0))(@better-auth/utils@0.4.0)(@better-fetch/fetch@1.1.21)(better-auth@1.6.11(@opentelemetry/api@1.9.1)(drizzle-orm@1.0.0-rc.3(@opentelemetry/api@1.9.1)(@types/pg@8.20.0)(effect@4.0.0-beta.70)(pg@8.21.0)(zod@4.4.3))(next@16.2.6(@babel/core@7.29.7)(@opentelemetry/api@1.9.1)(babel-plugin-macros@3.1.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(pg@8.21.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(vitest@4.1.7))(better-call@1.3.5(zod@4.4.3))': + '@better-auth/oauth-provider@1.6.11(@better-auth/core@1.6.11(@better-auth/utils@0.4.0)(@better-fetch/fetch@1.1.21)(@opentelemetry/api@1.9.1)(better-call@1.3.5(zod@4.4.3))(jose@6.2.3)(kysely@0.28.17)(nanostores@1.3.0))(@better-auth/utils@0.4.0)(@better-fetch/fetch@1.1.21)(better-auth@1.6.11(@opentelemetry/api@1.9.1)(drizzle-orm@1.0.0-rc.3(@opentelemetry/api@1.9.1)(@types/pg@8.20.0)(effect@4.0.0-beta.70)(pg@8.21.0)(zod@4.4.3))(next@16.2.6(@opentelemetry/api@1.9.1)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(pg@8.21.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(vitest@4.1.7))(better-call@1.3.5(zod@4.4.3))': dependencies: '@better-auth/core': 1.6.11(@better-auth/utils@0.4.0)(@better-fetch/fetch@1.1.21)(@opentelemetry/api@1.9.1)(better-call@1.3.5(zod@4.4.3))(jose@6.2.3)(kysely@0.28.17)(nanostores@1.3.0) '@better-auth/utils': 0.4.0 '@better-fetch/fetch': 1.1.21 - better-auth: 1.6.11(@opentelemetry/api@1.9.1)(drizzle-orm@1.0.0-rc.3(@opentelemetry/api@1.9.1)(@types/pg@8.20.0)(effect@4.0.0-beta.70)(pg@8.21.0)(zod@4.4.3))(next@16.2.6(@babel/core@7.29.7)(@opentelemetry/api@1.9.1)(babel-plugin-macros@3.1.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(pg@8.21.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(vitest@4.1.7) + better-auth: 1.6.11(@opentelemetry/api@1.9.1)(drizzle-orm@1.0.0-rc.3(@opentelemetry/api@1.9.1)(@types/pg@8.20.0)(effect@4.0.0-beta.70)(pg@8.21.0)(zod@4.4.3))(next@16.2.6(@opentelemetry/api@1.9.1)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(pg@8.21.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(vitest@4.1.7) better-call: 1.3.5(zod@4.4.3) jose: 6.2.3 zod: 4.4.3 - '@better-auth/passkey@1.6.11(@better-auth/core@1.6.11(@better-auth/utils@0.4.0)(@better-fetch/fetch@1.1.21)(@opentelemetry/api@1.9.1)(better-call@1.3.5(zod@4.4.3))(jose@6.2.3)(kysely@0.28.17)(nanostores@1.3.0))(@better-auth/utils@0.4.0)(@better-fetch/fetch@1.1.21)(better-auth@1.6.11(@opentelemetry/api@1.9.1)(drizzle-orm@1.0.0-rc.3(@opentelemetry/api@1.9.1)(@types/pg@8.20.0)(effect@4.0.0-beta.70)(pg@8.21.0)(zod@4.4.3))(next@16.2.6(@babel/core@7.29.7)(@opentelemetry/api@1.9.1)(babel-plugin-macros@3.1.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(pg@8.21.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(vitest@4.1.7))(better-call@1.3.5(zod@4.4.3))(nanostores@1.3.0)': + '@better-auth/passkey@1.6.11(@better-auth/core@1.6.11(@better-auth/utils@0.4.0)(@better-fetch/fetch@1.1.21)(@opentelemetry/api@1.9.1)(better-call@1.3.5(zod@4.4.3))(jose@6.2.3)(kysely@0.28.17)(nanostores@1.3.0))(@better-auth/utils@0.4.0)(@better-fetch/fetch@1.1.21)(better-auth@1.6.11(@opentelemetry/api@1.9.1)(drizzle-orm@1.0.0-rc.3(@opentelemetry/api@1.9.1)(@types/pg@8.20.0)(effect@4.0.0-beta.70)(pg@8.21.0)(zod@4.4.3))(next@16.2.6(@opentelemetry/api@1.9.1)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(pg@8.21.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(vitest@4.1.7))(better-call@1.3.5(zod@4.4.3))(nanostores@1.3.0)': dependencies: '@better-auth/core': 1.6.11(@better-auth/utils@0.4.0)(@better-fetch/fetch@1.1.21)(@opentelemetry/api@1.9.1)(better-call@1.3.5(zod@4.4.3))(jose@6.2.3)(kysely@0.28.17)(nanostores@1.3.0) '@better-auth/utils': 0.4.0 '@better-fetch/fetch': 1.1.21 '@simplewebauthn/browser': 13.3.0 '@simplewebauthn/server': 13.3.0 - better-auth: 1.6.11(@opentelemetry/api@1.9.1)(drizzle-orm@1.0.0-rc.3(@opentelemetry/api@1.9.1)(@types/pg@8.20.0)(effect@4.0.0-beta.70)(pg@8.21.0)(zod@4.4.3))(next@16.2.6(@babel/core@7.29.7)(@opentelemetry/api@1.9.1)(babel-plugin-macros@3.1.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(pg@8.21.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(vitest@4.1.7) + better-auth: 1.6.11(@opentelemetry/api@1.9.1)(drizzle-orm@1.0.0-rc.3(@opentelemetry/api@1.9.1)(@types/pg@8.20.0)(effect@4.0.0-beta.70)(pg@8.21.0)(zod@4.4.3))(next@16.2.6(@opentelemetry/api@1.9.1)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(pg@8.21.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(vitest@4.1.7) better-call: 1.3.5(zod@4.4.3) nanostores: 1.3.0 zod: 4.4.3 @@ -8704,12 +8707,12 @@ snapshots: '@better-auth/core': 1.6.11(@better-auth/utils@0.4.0)(@better-fetch/fetch@1.1.21)(@opentelemetry/api@1.9.1)(better-call@1.3.5(zod@4.4.3))(jose@6.2.3)(kysely@0.28.17)(nanostores@1.3.0) '@better-auth/utils': 0.4.0 - '@better-auth/sso@1.6.11(@better-auth/core@1.6.11(@better-auth/utils@0.4.0)(@better-fetch/fetch@1.1.21)(@opentelemetry/api@1.9.1)(better-call@1.3.5(zod@4.4.3))(jose@6.2.3)(kysely@0.28.17)(nanostores@1.3.0))(@better-auth/utils@0.4.0)(@better-fetch/fetch@1.1.21)(better-auth@1.6.11(@opentelemetry/api@1.9.1)(drizzle-orm@1.0.0-rc.3(@opentelemetry/api@1.9.1)(@types/pg@8.20.0)(effect@4.0.0-beta.70)(pg@8.21.0)(zod@4.4.3))(next@16.2.6(@babel/core@7.29.7)(@opentelemetry/api@1.9.1)(babel-plugin-macros@3.1.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(pg@8.21.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(vitest@4.1.7))(better-call@1.3.5(zod@4.4.3))': + '@better-auth/sso@1.6.11(@better-auth/core@1.6.11(@better-auth/utils@0.4.0)(@better-fetch/fetch@1.1.21)(@opentelemetry/api@1.9.1)(better-call@1.3.5(zod@4.4.3))(jose@6.2.3)(kysely@0.28.17)(nanostores@1.3.0))(@better-auth/utils@0.4.0)(@better-fetch/fetch@1.1.21)(better-auth@1.6.11(@opentelemetry/api@1.9.1)(drizzle-orm@1.0.0-rc.3(@opentelemetry/api@1.9.1)(@types/pg@8.20.0)(effect@4.0.0-beta.70)(pg@8.21.0)(zod@4.4.3))(next@16.2.6(@opentelemetry/api@1.9.1)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(pg@8.21.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(vitest@4.1.7))(better-call@1.3.5(zod@4.4.3))': dependencies: '@better-auth/core': 1.6.11(@better-auth/utils@0.4.0)(@better-fetch/fetch@1.1.21)(@opentelemetry/api@1.9.1)(better-call@1.3.5(zod@4.4.3))(jose@6.2.3)(kysely@0.28.17)(nanostores@1.3.0) '@better-auth/utils': 0.4.0 '@better-fetch/fetch': 1.1.21 - better-auth: 1.6.11(@opentelemetry/api@1.9.1)(drizzle-orm@1.0.0-rc.3(@opentelemetry/api@1.9.1)(@types/pg@8.20.0)(effect@4.0.0-beta.70)(pg@8.21.0)(zod@4.4.3))(next@16.2.6(@babel/core@7.29.7)(@opentelemetry/api@1.9.1)(babel-plugin-macros@3.1.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(pg@8.21.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(vitest@4.1.7) + better-auth: 1.6.11(@opentelemetry/api@1.9.1)(drizzle-orm@1.0.0-rc.3(@opentelemetry/api@1.9.1)(@types/pg@8.20.0)(effect@4.0.0-beta.70)(pg@8.21.0)(zod@4.4.3))(next@16.2.6(@opentelemetry/api@1.9.1)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(pg@8.21.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(vitest@4.1.7) better-call: 1.3.5(zod@4.4.3) fast-xml-parser: 5.8.0 jose: 6.2.3 @@ -11446,7 +11449,7 @@ snapshots: node-addon-api: 8.8.0 node-gyp-build: 4.8.4 - better-auth@1.6.11(@opentelemetry/api@1.9.1)(drizzle-orm@1.0.0-rc.3(@opentelemetry/api@1.9.1)(@types/pg@8.20.0)(effect@4.0.0-beta.70)(pg@8.21.0)(zod@4.4.3))(next@16.2.6(@babel/core@7.29.7)(@opentelemetry/api@1.9.1)(babel-plugin-macros@3.1.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(pg@8.21.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(vitest@4.1.7): + better-auth@1.6.11(@opentelemetry/api@1.9.1)(drizzle-orm@1.0.0-rc.3(@opentelemetry/api@1.9.1)(@types/pg@8.20.0)(effect@4.0.0-beta.70)(pg@8.21.0)(zod@4.4.3))(next@16.2.6(@opentelemetry/api@1.9.1)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(pg@8.21.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(vitest@4.1.7): dependencies: '@better-auth/core': 1.6.11(@better-auth/utils@0.4.0)(@better-fetch/fetch@1.1.21)(@opentelemetry/api@1.9.1)(better-call@1.3.5(zod@4.4.3))(jose@6.2.3)(kysely@0.28.17)(nanostores@1.3.0) '@better-auth/drizzle-adapter': 1.6.11(@better-auth/core@1.6.11(@better-auth/utils@0.4.0)(@better-fetch/fetch@1.1.21)(@opentelemetry/api@1.9.1)(better-call@1.3.5(zod@4.4.3))(jose@6.2.3)(kysely@0.28.17)(nanostores@1.3.0))(@better-auth/utils@0.4.0)(drizzle-orm@1.0.0-rc.3(@opentelemetry/api@1.9.1)(@types/pg@8.20.0)(effect@4.0.0-beta.70)(pg@8.21.0)(zod@4.4.3))