From 67f84c61ab447cf9ecef8fefd0aac3c6ebf2d2ef Mon Sep 17 00:00:00 2001 From: Nick the Sick Date: Fri, 18 Apr 2025 17:26:14 +0200 Subject: [PATCH 01/16] feat: implement better-auth & portal.sh --- docs/.gitignore | 1 + docs/app/api/auth/[...all]/route.ts | 4 + docs/app/api/auth/[...nextauth]/route.ts | 2 - docs/app/confirmation/page.tsx | 10 + docs/app/portal/page.tsx | 19 ++ docs/app/signup/page.tsx | 58 ++++ docs/auth.ts | 195 +++++--------- docs/components/AuthNavButton.tsx | 8 +- docs/components/example/ExampleBlock.tsx | 6 +- docs/components/example/index.tsx | 11 +- docs/package.json | 11 +- docs/pages/_app.tsx | 3 - docs/util/auth-client.ts | 7 + docs/util/authUtil.tsx | 16 -- package.json | 3 +- pnpm-lock.yaml | 325 ++++++++++++++++++++++- 16 files changed, 500 insertions(+), 179 deletions(-) create mode 100644 docs/app/api/auth/[...all]/route.ts delete mode 100644 docs/app/api/auth/[...nextauth]/route.ts create mode 100644 docs/app/confirmation/page.tsx create mode 100644 docs/app/portal/page.tsx create mode 100644 docs/app/signup/page.tsx create mode 100644 docs/util/auth-client.ts delete mode 100644 docs/util/authUtil.tsx diff --git a/docs/.gitignore b/docs/.gitignore index 1dd45b2022..af673ac194 100644 --- a/docs/.gitignore +++ b/docs/.gitignore @@ -37,3 +37,4 @@ next-env.d.ts # Sentry Config File .env.sentry-build-plugin +*.db \ No newline at end of file diff --git a/docs/app/api/auth/[...all]/route.ts b/docs/app/api/auth/[...all]/route.ts new file mode 100644 index 0000000000..a1953d1270 --- /dev/null +++ b/docs/app/api/auth/[...all]/route.ts @@ -0,0 +1,4 @@ +import { auth } from "../../../../auth"; +import { toNextJsHandler } from "better-auth/next-js"; + +export const { POST, GET } = toNextJsHandler(auth); \ No newline at end of file diff --git a/docs/app/api/auth/[...nextauth]/route.ts b/docs/app/api/auth/[...nextauth]/route.ts deleted file mode 100644 index 62da3d047a..0000000000 --- a/docs/app/api/auth/[...nextauth]/route.ts +++ /dev/null @@ -1,2 +0,0 @@ -export { GET, POST } from "../../../../auth"; -export const runtime = "edge"; // optional diff --git a/docs/app/confirmation/page.tsx b/docs/app/confirmation/page.tsx new file mode 100644 index 0000000000..939e55c7c3 --- /dev/null +++ b/docs/app/confirmation/page.tsx @@ -0,0 +1,10 @@ + +export default function Page({ + searchParams: { checkoutId }, +}: { + searchParams: { + checkoutId: string + } +}) { + return
Thank you! Your checkout is now being processed.
+} \ No newline at end of file diff --git a/docs/app/portal/page.tsx b/docs/app/portal/page.tsx new file mode 100644 index 0000000000..5c97ff74e9 --- /dev/null +++ b/docs/app/portal/page.tsx @@ -0,0 +1,19 @@ +"use client"; + +import { useSession } from "@/util/auth-client"; + +// Just shows session info +export default function Me() { + const { data: session } = useSession(); + + if (!session) { + return
Not authenticated
; + } + + return ( +
+

Welcome {session.user.name}

+
{JSON.stringify(session, null, 2)}
+
+ ); +}; \ No newline at end of file diff --git a/docs/app/signup/page.tsx b/docs/app/signup/page.tsx new file mode 100644 index 0000000000..1ec8a359c6 --- /dev/null +++ b/docs/app/signup/page.tsx @@ -0,0 +1,58 @@ +"use client"; + +import { signUp } from "@/util/auth-client"; +import { useState } from "react"; + +// TODO Do we want email & password signin? or just social? +export default function Register() { + const [name, setName] = useState(""); + const [email, setEmail] = useState(""); + const [password, setPassword] = useState(""); + + const handleRegister = async () => { + await signUp.email({ + email, + password, + name, + }); + }; + + return ( +
+

Register

+ setName(e.target.value)} + /> + setEmail(e.target.value)} + /> + setPassword(e.target.value)} + /> + +
+ ); +}; \ No newline at end of file diff --git a/docs/auth.ts b/docs/auth.ts index b0e8d09cdf..fc072c8746 100644 --- a/docs/auth.ts +++ b/docs/auth.ts @@ -1,138 +1,65 @@ -import NextAuth from "next-auth"; -import GitHub from "next-auth/providers/github"; +import { betterAuth } from "better-auth"; +import Database from "better-sqlite3"; +import { polar } from "@polar-sh/better-auth"; +import { Polar } from "@polar-sh/sdk"; +import { openAPI } from "better-auth/plugins" -export const { - handlers: { GET, POST }, - auth, - signIn, - signOut, -} = NextAuth({ - callbacks: { - signIn: async (params) => { - if (params.profile!.sponsorInfo) { - // user is sponsor - return true; - } - // user is signed in to github, but not a sponsor. - // TODO: We could redirect to pricing page here - return true; - // return "https://www.blocknotejs.org/pricing"; - }, - // https://authjs.dev/guides/extending-the-session - jwt({ token, user }) { - if (user) { - // User is available during sign-in - token.sponsorInfo = (user as any).sponsorInfo; - } - return token; - }, - session: async (params) => { - (params.session.user as any).sponsorInfo = ( - params.token as any - ).sponsorInfo; - return params.session; - }, +export const client = new Polar({ + accessToken: process.env.POLAR_ACCESS_TOKEN, + // Use 'sandbox' if you're using the Polar Sandbox environment + // Remember that access tokens, products, etc. are completely separated between environments. + // Access tokens obtained in Production are for instance not usable in the Sandbox environment. + server: 'sandbox' +}); + +export const auth = betterAuth({ + emailAndPassword: { + enabled: true }, - providers: [ - // copied from https://github.com/nextauthjs/next-auth/blob/234a150e2cac3bc62a9162fa00ed7cb16a105244/packages/core/src/providers/github.ts#L2, - // but with extra sponsorship api call - GitHub({ - userinfo: { - url: `https://api.github.com/user`, - async request({ tokens, provider }: any) { - const profile = await fetch(provider.userinfo?.url as URL, { - headers: { - Authorization: `Bearer ${tokens.access_token}`, - "User-Agent": "authjs", + socialProviders: { + github: { + clientId: process.env.AUTH_GITHUB_ID as string, + clientSecret: process.env.AUTH_GITHUB_SECRET as string + }, + }, + database: new Database("./sqlite.db"), + plugins: [ + // Just temporary for testing + // Serves on http://localhost:3000/api/auth/reference + openAPI(), + polar({ + client, + // Enable automatic Polar Customer creation on signup + createCustomerOnSignUp: true, + // http://localhost:3000/api/auth/portal + enableCustomerPortal: true, + // Configure checkout + checkout: { + enabled: true, + products: [ + { + productId: "8049f66f-fd0a-4690-a0aa-442ac5b03040", // ID of Product from Polar Dashboard + slug: "business" // Custom slug for easy reference in Checkout URL, e.g. /checkout/pro + // http://localhost:3000/api/auth/checkout/business + }, + { + productId: 'ab70fea5-172c-4aac-b3fc-0824f2a5b670', + slug: 'starter' + // http://localhost:3000/api/auth/checkout/starter + } + ], + // TODO set to actual page (welcome screen) + successUrl: "/success?checkout_id={CHECKOUT_ID}" }, - }).then(async (res) => await res.json()); - - if (!profile.email) { - // If the user does not have a public email, get another via the GitHub API - // See https://docs.github.com/en/rest/users/emails#list-public-email-addresses-for-the-authenticated-user - const res = await fetch(`https://api.github.com/user/emails`, { - headers: { - Authorization: `Bearer ${tokens.access_token}`, - "User-Agent": "authjs", - }, - }); - - if (res.ok) { - const emails: any[] = await res.json(); - profile.email = ( - emails.find((e) => e.primary) ?? emails[0] - ).email; + // Incoming Webhooks handler will be installed at /polar/webhooks + webhooks: { + // webhooks have to be publicly accessible + // ngrok http http://localhost:3000 + secret: process.env.POLAR_WEBHOOK_SECRET as string, + onPayload: async (payload) => { + console.log(payload) + }, } - } - - const resSponsor = await fetch(`https://api.github.com/graphql`, { - method: "POST", - headers: { - "Content-Type": "application/json", - Authorization: `Bearer ${tokens.access_token}`, - }, - // organization(login:"TypeCellOS") { - // user(login:"YousefED") { - body: JSON.stringify({ - query: `{ - user(login:"YousefED") { - sponsorshipForViewerAsSponsor(activeOnly:false) { - isActive, - tier { - name - monthlyPriceInDollars - } - } - } - }`, - }), - }); - - if (resSponsor.ok) { - // Mock data. TODO: disable and test actial data - // profile.sponsorInfo = { - // isActive: true, - // tier: { - // name: "test", - // monthlyPriceInDollars: 100, - // }, - // }; - // use API data: - - const data = await resSponsor.json(); - // eslint-disable-next-line no-console - console.log("sponsor data", data); - - // { - // "data": { - // "user": { - // "sponsorshipForViewerAsSponsor": { - // "isActive": true, - // "tier": { - // "name": "$90 a month", - // "monthlyPriceInDollars": 90 - // } - // } - // } - // } - // } - - profile.sponsorInfo = data.data.user.sponsorshipForViewerAsSponsor; - } - - return profile; - }, - }, - profile: (profile) => { - return { - id: profile.id.toString(), - name: profile.name ?? profile.login, - email: profile.email, - image: profile.avatar_url, - username: profile.login, - sponsorInfo: profile.sponsorInfo, - }; - }, - }), - ], -}); + }) + ] +}); \ No newline at end of file diff --git a/docs/components/AuthNavButton.tsx b/docs/components/AuthNavButton.tsx index 568e2249ea..57cba5e7f9 100644 --- a/docs/components/AuthNavButton.tsx +++ b/docs/components/AuthNavButton.tsx @@ -1,13 +1,13 @@ import { Menu, Transition } from "@headlessui/react"; import clsx from "clsx"; -import { signOut, useSession } from "next-auth/react"; +import { authClient } from "@/util/auth-client"; import Image from "next/image"; import { ReactElement, ReactNode } from "react"; export function AuthNavButton(props: any) { - const session = useSession(); + const session = authClient.useSession(); - return session.status === "authenticated" ? ( + return session.data ? ( @@ -22,7 +22,7 @@ export function AuthNavButton(props: any) { {" "} diff --git a/docs/components/example/index.tsx b/docs/components/example/index.tsx index 2db9d6947e..a1f5ee4e3d 100644 --- a/docs/components/example/index.tsx +++ b/docs/components/example/index.tsx @@ -1,20 +1,23 @@ import { useSession } from "next-auth/react"; -import { getProLevel } from "../../util/authUtil"; +// import { authClient } from "../../util/auth-client"; import { examples } from "./generated/exampleComponents.gen"; +import { authClient } from "@/util/auth-client"; export function Example(props: { name: keyof typeof examples }) { - const session = useSession(); + // authClient. + const session = authClient.useSession() + // const session = useSession(); const example = examples[props.name]; if (!example) { throw new Error(`Example ${props.name} not found`); } const ExampleWithCode = example.ExampleWithCode; - const userStatus = getProLevel(session); + // const userStatus = getProLevel(session); return ( ); } diff --git a/docs/package.json b/docs/package.json index a5ff4a43c4..420b02f74a 100644 --- a/docs/package.json +++ b/docs/package.json @@ -10,8 +10,8 @@ }, "dependencies": { "@blocknote/ariakit": "workspace:^", - "@blocknote/core": "workspace:^", "@blocknote/code-block": "workspace:^", + "@blocknote/core": "workspace:^", "@blocknote/mantine": "workspace:^", "@blocknote/react": "workspace:^", "@blocknote/shadcn": "workspace:^", @@ -20,9 +20,15 @@ "@heroicons/react": "^2.1.4", "@mantine/core": "^7.10.1", "@next/bundle-analyzer": "^14.1.0", + "@polar-sh/better-auth": "0.1.0", + "@polar-sh/nextjs": "0.3.23", + "@polar-sh/sdk": "0.32.10", "@sentry/nextjs": "9.4.0", + "@types/better-sqlite3": "7.6.13", "@vercel/analytics": "^1.2.2", "@vercel/og": "^0.6.2", + "better-auth": "1.2.7", + "better-sqlite3": "11.9.1", "classnames": "2.3.2", "clsx": "^2.1.0", "framer-motion": "^10.16.16", @@ -37,7 +43,8 @@ "react-github-btn": "^1.4.0", "react-icons": "^5.2.1", "y-partykit": "^0.0.25", - "yjs": "^13.6.15" + "yjs": "^13.6.15", + "zod": "^3.23.8" }, "devDependencies": { "@types/node": "^20", diff --git a/docs/pages/_app.tsx b/docs/pages/_app.tsx index c2888af87e..24644c1eb0 100644 --- a/docs/pages/_app.tsx +++ b/docs/pages/_app.tsx @@ -1,6 +1,5 @@ // import "../custom.css"; import { Analytics } from "@vercel/analytics/react"; -import { SessionProvider } from "next-auth/react"; import type { AppProps } from "next/app"; import { type ReactNode } from "react"; import "../styles.css"; @@ -16,10 +15,8 @@ export default function Nextra({ Component, pageProps }: NextraAppProps) { return ( <> - - ); } diff --git a/docs/util/auth-client.ts b/docs/util/auth-client.ts new file mode 100644 index 0000000000..314e890ab5 --- /dev/null +++ b/docs/util/auth-client.ts @@ -0,0 +1,7 @@ +import { createAuthClient } from "better-auth/react" +export const authClient = createAuthClient({ + /** The base URL of the server (optional if you're using the same domain) */ + baseURL: "http://localhost:3000" +}) + +export const { useSession, signIn, signOut, signUp } = authClient \ No newline at end of file diff --git a/docs/util/authUtil.tsx b/docs/util/authUtil.tsx deleted file mode 100644 index 8c265b0dc2..0000000000 --- a/docs/util/authUtil.tsx +++ /dev/null @@ -1,16 +0,0 @@ -import type { useSession } from "next-auth/react"; - -export function getProLevel( - session: ReturnType, -): "business" | "starter" | "free" | undefined { - if (session.status !== "authenticated") { - return undefined; - } - - const sponsorInfo = (session?.data?.user as any)?.sponsorInfo; - if (!sponsorInfo?.isActive) { - return "free"; - } - - return sponsorInfo.tier.monthlyPriceInDollars > 100 ? "business" : "starter"; -} diff --git a/package.json b/package.json index a4a34feee3..9f8c9ba0ec 100644 --- a/package.json +++ b/package.json @@ -25,7 +25,8 @@ "@sentry/cli", "canvas", "esbuild", - "nx" + "nx", + "better-sqlite3" ] }, "packageManager": "pnpm@10.7.1+sha512.2d92c86b7928dc8284f53494fb4201f983da65f0fb4f0d40baafa5cf628fa31dae3e5968f12466f17df7e97310e30f343a648baea1b9b350685dafafffdf5808", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 4a82205cdc..b559c56a90 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -83,15 +83,33 @@ importers: '@next/bundle-analyzer': specifier: ^14.1.0 version: 14.2.26 + '@polar-sh/better-auth': + specifier: 0.1.0 + version: 0.1.0(@polar-sh/sdk@0.32.10(zod@3.24.2))(better-auth@1.2.7) + '@polar-sh/nextjs': + specifier: 0.3.23 + version: 0.3.23(next@15.2.4(@babel/core@7.26.10)(@opentelemetry/api@1.9.0)(@playwright/test@1.51.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(zod@3.24.2) + '@polar-sh/sdk': + specifier: 0.32.10 + version: 0.32.10(zod@3.24.2) '@sentry/nextjs': specifier: 9.4.0 version: 9.4.0(@opentelemetry/context-async-hooks@1.30.1(@opentelemetry/api@1.9.0))(@opentelemetry/core@1.30.1(@opentelemetry/api@1.9.0))(@opentelemetry/instrumentation@0.57.2(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@1.30.1(@opentelemetry/api@1.9.0))(encoding@0.1.13)(next@15.2.4(@babel/core@7.26.10)(@opentelemetry/api@1.9.0)(@playwright/test@1.51.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1)(webpack@5.98.0) + '@types/better-sqlite3': + specifier: 7.6.13 + version: 7.6.13 '@vercel/analytics': specifier: ^1.2.2 version: 1.5.0(next@15.2.4(@babel/core@7.26.10)(@opentelemetry/api@1.9.0)(@playwright/test@1.51.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1) '@vercel/og': specifier: ^0.6.2 version: 0.6.5 + better-auth: + specifier: 1.2.7 + version: 1.2.7 + better-sqlite3: + specifier: 11.9.1 + version: 11.9.1 classnames: specifier: 2.3.2 version: 2.3.2 @@ -137,6 +155,9 @@ importers: yjs: specifier: ^13.6.15 version: 13.6.24 + zod: + specifier: ^3.23.8 + version: 3.24.2 devDependencies: '@types/node': specifier: ^20 @@ -4714,6 +4735,12 @@ packages: '@base2/pretty-print-object@1.0.1': resolution: {integrity: sha512-4iri8i1AqYHJE2DstZYkyEprg6Pq6sKx3xn5FpySk9sNhH7qN2LLlHJCfDTZRILNwQNPD7mATWM0TBui7uC1pA==} + '@better-auth/utils@0.2.4': + resolution: {integrity: sha512-ayiX87Xd5sCHEplAdeMgwkA0FgnXsEZBgDn890XHHwSWNqqRZDYOq3uj2Ei2leTv1I2KbG5HHn60Ah1i2JWZjQ==} + + '@better-fetch/fetch@1.1.18': + resolution: {integrity: sha512-rEFOE1MYIsBmoMJtQbl32PGHHXuG2hDxvEd7rUHE0vCBoFQVSDqaVs9hkZEtHCxRoY+CljXKFCOuJ8uxqw1LcA==} + '@braintree/sanitize-url@6.0.4': resolution: {integrity: sha512-s3jaWicZd0pkP0jf5ysyHUI/RE7MHos6qlToFcGWXVp+ykHOy77OUMrfbgJ9it2C5bow7OIQwYYaHjk9XlBQ2A==} @@ -5348,6 +5375,9 @@ packages: peerDependencies: react: '>= 16 || ^19.0.0-rc' + '@hexagon/base64@1.1.28': + resolution: {integrity: sha512-lhqDEAvWixy3bZ+UOYbPwUbBkwBq5C1LAJ/xPC8Oi+lL54oyakv/npbA0aU2hgCsx/1NUd4IBvV03+aUBWxerw==} + '@hocuspocus/common@2.15.2': resolution: {integrity: sha512-wU1wxXNnQQMXyeL3mdSDYiQsm/r/QyJVjjQhF7sUBrLnjdsN7bA1cvfcSvJBr1ymrMSeYRmUL3UlQmEHEOaP7w==} @@ -5523,6 +5553,9 @@ packages: '@juggle/resize-observer@3.4.0': resolution: {integrity: sha512-dfLbk+PwWvFzSxwk3n5ySL0hfBog779o8h68wK/7/APo/7cgyWp5jcXockbxdk5kFRkbeXWm4Fbi9FrdN381sA==} + '@levischuck/tiny-cbor@0.2.11': + resolution: {integrity: sha512-llBRm4dT4Z89aRsm6u2oEZ8tfwL/2l6BwpZ7JcyieouniDECM5AqNgr/y08zalEIvW3RSK4upYyybDcmjXqAow==} + '@lifeomic/attempt@3.1.0': resolution: {integrity: sha512-QZqem4QuAnAyzfz+Gj5/+SLxqwCAw2qmt7732ZXodr6VDWGeYLG6w1i/vYLa55JQM9wRuBKLmXmiZ2P0LtE5rw==} @@ -5838,6 +5871,13 @@ packages: '@nicolo-ribaudo/eslint-scope-5-internals@5.1.1-v1': resolution: {integrity: sha512-54/JRvkLIzzDWshCWfuhadfrfZVPiElY8Fcgmg1HroEly/EDSszzhBAsarCux+D/kOslTRquNzuyGSmUSTTHGg==} + '@noble/ciphers@0.6.0': + resolution: {integrity: sha512-mIbq/R9QXk5/cTfESb1OKtyFnk7oc1Om/8onA1158K9/OZUQFDEVy55jVTato+xmp3XX6F6Qh0zz0Nc1AxAlRQ==} + + '@noble/hashes@1.7.2': + resolution: {integrity: sha512-biZ0NUSxyjLLqo6KxEJ1b+C2NAx0wtDoFvCaXHGgUkeHzf3Xc1xKumFKREuT7f7DARNZ/slvYUwFG6B0f2b6hQ==} + engines: {node: ^14.21.3 || >=16} + '@nodelib/fs.scandir@2.1.5': resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} engines: {node: '>= 8'} @@ -6127,6 +6167,21 @@ packages: '@panva/hkdf@1.2.1': resolution: {integrity: sha512-6oclG6Y3PiDFcoyk8srjLfVKyMfVCKJ27JwNPViuXziFpmdz+MZnZN/aKY0JGXgYuO/VghU0jcOAZgWXZ1Dmrw==} + '@peculiar/asn1-android@2.3.16': + resolution: {integrity: sha512-a1viIv3bIahXNssrOIkXZIlI2ePpZaNmR30d4aBL99mu2rO+mT9D6zBsp7H6eROWGtmwv0Ionp5olJurIo09dw==} + + '@peculiar/asn1-ecc@2.3.15': + resolution: {integrity: sha512-/HtR91dvgog7z/WhCVdxZJ/jitJuIu8iTqiyWVgRE9Ac5imt2sT/E4obqIVGKQw7PIy+X6i8lVBoT6wC73XUgA==} + + '@peculiar/asn1-rsa@2.3.15': + resolution: {integrity: sha512-p6hsanvPhexRtYSOHihLvUUgrJ8y0FtOM97N5UEpC+VifFYyZa0iZ5cXjTkZoDwxJ/TTJ1IJo3HVTB2JJTpXvg==} + + '@peculiar/asn1-schema@2.3.15': + resolution: {integrity: sha512-QPeD8UA8axQREpgR5UTAfu2mqQmm97oUqahDtNdBcfj3qAnoXzFdQW+aNf/tD2WVXF8Fhmftxoj0eMIT++gX2w==} + + '@peculiar/asn1-x509@2.3.15': + resolution: {integrity: sha512-0dK5xqTqSLaxv1FHXIcd4Q/BZNuopg+u1l23hT9rOmQ1g4dNtw0g/RnEi+TboB0gOwGtrWn269v27cMgchFIIg==} + '@pkgjs/parseargs@0.11.0': resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} engines: {node: '>=14'} @@ -6145,6 +6200,32 @@ packages: engines: {node: '>=18'} hasBin: true + '@polar-sh/adapter-utils@0.1.15': + resolution: {integrity: sha512-hYHdvFRAaV8Z8FrPYZX2uTxEVwHNKy/woLFDn5SSxPo+Uqmrog7a/v8XZN7T9Sz8UePTFRUY6m+QbEBAPjDK9A==} + + '@polar-sh/better-auth@0.1.0': + resolution: {integrity: sha512-Gw67CoLoPIelwpa+BR7cMZb/i8MJP2g2E93MhEl26OuWGt8xNbAqzXasDoyUgZQ/r6ZwwdYPRzUqMWmwnRTEqQ==} + engines: {node: '>=16'} + peerDependencies: + '@polar-sh/sdk': ^0.32.11 + better-auth: ^1.2.0 + + '@polar-sh/nextjs@0.3.23': + resolution: {integrity: sha512-AiQDffXnpaydBeCghDsBaGHTanUEG2039JbukDCBbbbzgbjdl1NpgpmPh62le+Fl0f+s21qU+ZCnwEeJJelrTg==} + engines: {node: '>=16'} + peerDependencies: + next: ^15.0.0 || ^15.2.0-canary.* + + '@polar-sh/sdk@0.32.10': + resolution: {integrity: sha512-k7og3L1RP7kTRFVSxiVF4GIkTy/JQwfUY4D1aqSEnj3OtR13NjHsAW2Rb6bEJDuws2/bzfAVQvbQTxf+VsmK9A==} + hasBin: true + peerDependencies: + '@modelcontextprotocol/sdk': ^1.5.0 + zod: '>= 3' + peerDependenciesMeta: + '@modelcontextprotocol/sdk': + optional: true + '@polka/url@1.0.0-next.28': resolution: {integrity: sha512-8LduaNlMZGwdZ6qWrKlfa+2M4gahzFkprZiAt2TF8uS0qQgBizKXpXURqvTJ4WtmupWxaLqjRb2UCTe72mu+Aw==} @@ -6878,6 +6959,13 @@ packages: '@sideway/pinpoint@2.0.0': resolution: {integrity: sha512-RNiOoTPkptFtSVzQevY/yWtZwf/RxyVnPy/OcA9HBM3MlGDnBEYL5B41H0MTn0Uec8Hi+2qUtTfG2WWZBmMejQ==} + '@simplewebauthn/browser@13.1.0': + resolution: {integrity: sha512-WuHZ/PYvyPJ9nxSzgHtOEjogBhwJfC8xzYkPC+rR/+8chl/ft4ngjiK8kSU5HtRJfczupyOh33b25TjYbvwAcg==} + + '@simplewebauthn/server@13.1.1': + resolution: {integrity: sha512-1hsLpRHfSuMB9ee2aAdh0Htza/X3f4djhYISrggqGe3xopNjOcePiSDkDDoPzDYaaMCrbqGP1H2TYU7bgL9PmA==} + engines: {node: '>=20.0.0'} + '@sinclair/typebox@0.27.8': resolution: {integrity: sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==} @@ -7093,6 +7181,9 @@ packages: resolution: {integrity: sha512-JtaY3FxmD+te+KSI2FJuEcfNC9T/DGGVf551babM7fAaXhjJUt7oSYurH1Devxd2+BOSUACCgt3buinx4UnmEA==} engines: {node: '>=18.0.0'} + '@stablelib/base64@1.0.1': + resolution: {integrity: sha512-1bnPQqSxSuc3Ii6MhBysoWCg58j97aUjuCSZrGSmDxNqtytIi0k8utUenAwTZN4V5mXXYGsVUI9zeBqy+jBOSQ==} + '@swc/counter@0.1.3': resolution: {integrity: sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==} @@ -7284,6 +7375,9 @@ packages: '@types/babel__traverse@7.20.7': resolution: {integrity: sha512-dkO5fhS7+/oos4ciWxyEyjWe48zmG6wbCheo/G2ZnHx4fs3EU6YC6UM8rk56gAjNJ9P3MTH2jo5jb92/K6wbng==} + '@types/better-sqlite3@7.6.13': + resolution: {integrity: sha512-NMv9ASNARoKksWtsq/SHakpYAYnhBrQgGD8zkLYk/jaK8jUGn08CfEdTRgYhMypUQAfzSP8W6gNLe0q19/t4VA==} + '@types/connect@3.4.38': resolution: {integrity: sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==} @@ -8051,6 +8145,10 @@ packages: as-table@1.0.55: resolution: {integrity: sha512-xvsWESUJn0JN421Xb9MQw6AsMHRCUknCe0Wjlxvjud80mU4E6hQf1A6NzQKcYNmYw62MfzEtXc+badstZP3JpQ==} + asn1js@3.0.6: + resolution: {integrity: sha512-UOCGPYbl0tv8+006qks/dTgV9ajs97X2p0FAbyS2iyCRrmLSRolDaHdp+v/CLgnzHc3fVB+CwYiUmei7ndFcgA==} + engines: {node: '>=12.0.0'} + assertion-error@2.0.1: resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==} engines: {node: '>=12'} @@ -8146,6 +8244,15 @@ packages: base64-js@1.5.1: resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} + better-auth@1.2.7: + resolution: {integrity: sha512-2hCB263GSrgetsMUZw8vv9O1e4S4AlYJW3P4e8bX9u3Q3idv4u9BzDFCblpTLuL4YjYovghMCN0vurAsctXOAQ==} + + better-call@1.0.8: + resolution: {integrity: sha512-/PV8JLqDRUN7JyBPbklVsS/8E4SO3pnf8hbpa8B7xrBrr+BBYpeOAxoqtnsyk/pRs35vNB4MZx8cn9dBuNlLDA==} + + better-sqlite3@11.9.1: + resolution: {integrity: sha512-Ba0KR+Fzxh2jDRhdg6TSH0SJGzb8C0aBY4hR8w8madIdIzzC6Y1+kx5qR6eS1Z+Gy20h6ZU28aeyg0z1VIrShQ==} + bidi-js@1.0.3: resolution: {integrity: sha512-RKshQI1R3YQ+n9YJz2QQ147P66ELpa1FQEg20Dk8oW9t2KgLbpDLLp9aGZ7y8WHSshDknG0bknqGw5/tyCs5tw==} @@ -8156,6 +8263,9 @@ packages: resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==} engines: {node: '>=8'} + bindings@1.5.0: + resolution: {integrity: sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==} + bl@4.1.0: resolution: {integrity: sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==} @@ -8779,6 +8889,9 @@ packages: resolution: {integrity: sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==} engines: {node: '>= 0.4'} + defu@6.1.4: + resolution: {integrity: sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg==} + delaunator@5.0.1: resolution: {integrity: sha512-8nvh+XBe96aCESrGOqMp/84b13H9cdKbG5P2ejQCh4d4sK9RL4371qou9drQjMhvnPmhWl5hnmqbEE0fXr9Xnw==} @@ -9257,6 +9370,9 @@ packages: fast-levenshtein@2.0.6: resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} + fast-sha256@1.3.0: + resolution: {integrity: sha512-n11RGP/lrWEFI/bWdygLxhI+pVeo1ZYIVwvvPkW7azl/rOy+F3HYRZ2K5zeE9mmkhQppyv9sQFx0JM9UabnpPQ==} + fast-uri@3.0.6: resolution: {integrity: sha512-Atfo14OibSv5wAp4VWNsFYE1AchQRTv9cBGWET4pZWHzYshFSS9NQI6I57rdKn9croWVMbYFbLhJ+yJvmZIIHw==} @@ -9289,6 +9405,9 @@ packages: resolution: {integrity: sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==} engines: {node: ^10.12.0 || >=12.0.0} + file-uri-to-path@1.0.0: + resolution: {integrity: sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==} + filelist@1.0.4: resolution: {integrity: sha512-w1cEuf3S+DrLCQL7ET6kz+gmlJdbq9J7yXCSjK/OZCPA+qEN1WyF4ZAf0YYJa4/shHJra2t/d/r8SV4Ji+x+8Q==} @@ -10165,6 +10284,10 @@ packages: resolution: {integrity: sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==} engines: {node: '>=6'} + kysely@0.27.6: + resolution: {integrity: sha512-FIyV/64EkKhJmjgC0g2hygpBv5RNWVPyNCqSAD7eTCv6eFWNIi4PN1UvdSJGicN/o35bnevgis4Y0UDC0qi8jQ==} + engines: {node: '>=14.0.0'} + language-subtag-registry@0.3.23: resolution: {integrity: sha512-0K65Lea881pHotoGEa5gDlMxt3pctLi2RplBb7Ezh4rRdLEOtgi7n4EwK9lamnUCkKBqaeKRVebTq6BAxSkpXQ==} @@ -10739,6 +10862,10 @@ packages: engines: {node: ^18 || >=20} hasBin: true + nanostores@0.11.4: + resolution: {integrity: sha512-k1oiVNN4hDK8NcNERSZLQiMfRzEGtfnvZvdBvey3SQbgn8Dcrk0h1I6vpxApjb10PFUflZrgJ2WEZyJQ+5v7YQ==} + engines: {node: ^18.0.0 || >=20.0.0} + napi-build-utils@2.0.0: resolution: {integrity: sha512-GEbrYkbfF7MoNaoh2iGG84Mnf/WZfB0GdGEsM8wz7Expx/LlWf5U8t9nvJKXSp3qr5IsEbK04cBGhol/KwOsWA==} @@ -11462,6 +11589,13 @@ packages: resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} engines: {node: '>=6'} + pvtsutils@1.3.6: + resolution: {integrity: sha512-PLgQXQ6H2FWCaeRak8vvk1GW462lMxB5s3Jm673N82zI4vqtVUPuZdffdZbPDFRoU8kAhItWFtPCWiPpp4/EDg==} + + pvutils@1.1.3: + resolution: {integrity: sha512-pMpnA0qRdFp32b1sJl1wOJNxZLQ2cbQx+k6tjNtZ8CpvVhNqEPRgivZ2WOUev2YMajecdH7ctUPDvEe87nariQ==} + engines: {node: '>=6.0.0'} + querystringify@2.2.0: resolution: {integrity: sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==} @@ -11822,6 +11956,9 @@ packages: rope-sequence@1.3.4: resolution: {integrity: sha512-UT5EDe2cu2E/6O4igUr5PSFs23nvvukicWHx6GnOPlHAiiYbzNuCRQCuiUdHJQcqKalLKlrYJnjY0ySGsXNQXQ==} + rou3@0.5.1: + resolution: {integrity: sha512-OXMmJ3zRk2xeXFGfA3K+EOPHC5u7RDFG7lIOx0X1pdnhUkI8MdVrbV+sNsD80ElpUZ+MRHdyxPnFthq9VHs8uQ==} + rrweb-cssom@0.6.0: resolution: {integrity: sha512-APM0Gt1KoXBz0iIkkdB/kfvGOwC4UuJFeG/c+yV7wSc7q96cG/kJ0HiYCnzivD9SB53cLV1MlHFNfOuPaadYSw==} @@ -11920,6 +12057,9 @@ packages: set-blocking@2.0.0: resolution: {integrity: sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==} + set-cookie-parser@2.7.1: + resolution: {integrity: sha512-IOc8uWeOZgnb3ptbCURJWNjWUPcO3ZnTTdzsurqERrP6nPyv+paC55vJM0LpOlT2ne+Ix+9+CRG1MNLlyZ4GjQ==} + set-function-length@1.2.2: resolution: {integrity: sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==} engines: {node: '>= 0.4'} @@ -12087,6 +12227,9 @@ packages: stacktracey@2.1.8: resolution: {integrity: sha512-Kpij9riA+UNg7TnphqjH7/CzctQ/owJGNbFkfEeve4Z4uxT5+JapVLFXcsurIfN34gnTWZNJ/f7NMG0E8JDzTw==} + standardwebhooks@1.0.0: + resolution: {integrity: sha512-BbHGOQK9olHPMvQNHWul6MYlrRTAOKn03rOe4A8O3CLWhNf4YHBqq2HJKKC+sfqpxiBY52pNeesD6jIiLDz8jg==} + std-env@3.8.1: resolution: {integrity: sha512-vj5lIj3Mwf9D79hBkltk5qmkFI+biIKWS2IBxEyEU3AX1tUf7AoL8nSazCOiiqQsGKIq01SClsKEzweu34uwvA==} @@ -12477,6 +12620,9 @@ packages: resolution: {integrity: sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==} engines: {node: '>= 0.4'} + uncrypto@0.1.3: + resolution: {integrity: sha512-Ql87qFHB3s/De2ClA9e0gsnS6zXG27SkTiSJwjCc9MebbfapQfuPzumMIUMi38ezPZVNFcHI9sUIepeQfw8J8Q==} + undici-types@6.19.8: resolution: {integrity: sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==} @@ -14415,6 +14561,13 @@ snapshots: '@base2/pretty-print-object@1.0.1': {} + '@better-auth/utils@0.2.4': + dependencies: + typescript: 5.8.2 + uncrypto: 0.1.3 + + '@better-fetch/fetch@1.1.18': {} + '@braintree/sanitize-url@6.0.4': {} '@cloudflare/workerd-darwin-64@1.20240129.0': @@ -14848,6 +15001,8 @@ snapshots: dependencies: react: 18.3.1 + '@hexagon/base64@1.1.28': {} + '@hocuspocus/common@2.15.2': dependencies: lib0: 0.2.101 @@ -14977,7 +15132,7 @@ snapshots: '@jest/schemas': 29.6.3 '@types/istanbul-lib-coverage': 2.0.6 '@types/istanbul-reports': 3.0.4 - '@types/node': 20.17.28 + '@types/node': 20.17.30 '@types/yargs': 17.0.33 chalk: 4.1.2 @@ -15010,6 +15165,8 @@ snapshots: '@juggle/resize-observer@3.4.0': {} + '@levischuck/tiny-cbor@0.2.11': {} + '@lifeomic/attempt@3.1.0': {} '@liveblocks/client@2.22.3': @@ -15374,6 +15531,10 @@ snapshots: dependencies: eslint-scope: 5.1.1 + '@noble/ciphers@0.6.0': {} + + '@noble/hashes@1.7.2': {} + '@nodelib/fs.scandir@2.1.5': dependencies: '@nodelib/fs.stat': 2.0.5 @@ -15737,6 +15898,39 @@ snapshots: '@panva/hkdf@1.2.1': {} + '@peculiar/asn1-android@2.3.16': + dependencies: + '@peculiar/asn1-schema': 2.3.15 + asn1js: 3.0.6 + tslib: 2.8.1 + + '@peculiar/asn1-ecc@2.3.15': + dependencies: + '@peculiar/asn1-schema': 2.3.15 + '@peculiar/asn1-x509': 2.3.15 + asn1js: 3.0.6 + tslib: 2.8.1 + + '@peculiar/asn1-rsa@2.3.15': + dependencies: + '@peculiar/asn1-schema': 2.3.15 + '@peculiar/asn1-x509': 2.3.15 + asn1js: 3.0.6 + tslib: 2.8.1 + + '@peculiar/asn1-schema@2.3.15': + dependencies: + asn1js: 3.0.6 + pvtsutils: 1.3.6 + tslib: 2.8.1 + + '@peculiar/asn1-x509@2.3.15': + dependencies: + '@peculiar/asn1-schema': 2.3.15 + asn1js: 3.0.6 + pvtsutils: 1.3.6 + tslib: 2.8.1 + '@pkgjs/parseargs@0.11.0': optional: true @@ -15775,6 +15969,33 @@ snapshots: dependencies: playwright: 1.51.1 + '@polar-sh/adapter-utils@0.1.15(zod@3.24.2)': + dependencies: + '@polar-sh/sdk': 0.32.10(zod@3.24.2) + transitivePeerDependencies: + - '@modelcontextprotocol/sdk' + - zod + + '@polar-sh/better-auth@0.1.0(@polar-sh/sdk@0.32.10(zod@3.24.2))(better-auth@1.2.7)': + dependencies: + '@polar-sh/sdk': 0.32.10(zod@3.24.2) + better-auth: 1.2.7 + zod: 3.24.2 + + '@polar-sh/nextjs@0.3.23(next@15.2.4(@babel/core@7.26.10)(@opentelemetry/api@1.9.0)(@playwright/test@1.51.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(zod@3.24.2)': + dependencies: + '@polar-sh/adapter-utils': 0.1.15(zod@3.24.2) + '@polar-sh/sdk': 0.32.10(zod@3.24.2) + next: 15.2.4(@babel/core@7.26.10)(@opentelemetry/api@1.9.0)(@playwright/test@1.51.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + transitivePeerDependencies: + - '@modelcontextprotocol/sdk' + - zod + + '@polar-sh/sdk@0.32.10(zod@3.24.2)': + dependencies: + standardwebhooks: 1.0.0 + zod: 3.24.2 + '@polka/url@1.0.0-next.28': {} '@popperjs/core@2.11.8': {} @@ -16603,6 +16824,18 @@ snapshots: '@sideway/pinpoint@2.0.0': {} + '@simplewebauthn/browser@13.1.0': {} + + '@simplewebauthn/server@13.1.1': + dependencies: + '@hexagon/base64': 1.1.28 + '@levischuck/tiny-cbor': 0.2.11 + '@peculiar/asn1-android': 2.3.16 + '@peculiar/asn1-ecc': 2.3.15 + '@peculiar/asn1-rsa': 2.3.15 + '@peculiar/asn1-schema': 2.3.15 + '@peculiar/asn1-x509': 2.3.15 + '@sinclair/typebox@0.27.8': {} '@smithy/abort-controller@4.0.2': @@ -16936,6 +17169,8 @@ snapshots: '@smithy/types': 4.2.0 tslib: 2.8.1 + '@stablelib/base64@1.0.1': {} + '@swc/counter@0.1.3': {} '@swc/helpers@0.5.15': @@ -17145,9 +17380,13 @@ snapshots: dependencies: '@babel/types': 7.27.0 + '@types/better-sqlite3@7.6.13': + dependencies: + '@types/node': 20.17.30 + '@types/connect@3.4.38': dependencies: - '@types/node': 20.17.28 + '@types/node': 20.17.30 '@types/cookie@0.6.0': {} @@ -17270,7 +17509,7 @@ snapshots: '@types/mysql@2.15.26': dependencies: - '@types/node': 20.17.28 + '@types/node': 20.17.30 '@types/node@20.17.28': dependencies: @@ -17292,7 +17531,7 @@ snapshots: '@types/pg@8.6.1': dependencies: - '@types/node': 20.17.28 + '@types/node': 20.17.30 pg-protocol: 1.8.0 pg-types: 2.2.0 @@ -17329,7 +17568,7 @@ snapshots: '@types/tedious@4.0.14': dependencies: - '@types/node': 20.17.28 + '@types/node': 20.17.30 '@types/tough-cookie@4.0.5': {} @@ -18028,6 +18267,12 @@ snapshots: dependencies: printable-characters: 1.0.42 + asn1js@3.0.6: + dependencies: + pvtsutils: 1.3.6 + pvutils: 1.1.3 + tslib: 2.8.1 + assertion-error@2.0.1: {} ast-types-flow@0.0.8: {} @@ -18144,6 +18389,33 @@ snapshots: base64-js@1.5.1: {} + better-auth@1.2.7: + dependencies: + '@better-auth/utils': 0.2.4 + '@better-fetch/fetch': 1.1.18 + '@noble/ciphers': 0.6.0 + '@noble/hashes': 1.7.2 + '@simplewebauthn/browser': 13.1.0 + '@simplewebauthn/server': 13.1.1 + better-call: 1.0.8 + defu: 6.1.4 + jose: 5.10.0 + kysely: 0.27.6 + nanostores: 0.11.4 + zod: 3.24.2 + + better-call@1.0.8: + dependencies: + '@better-fetch/fetch': 1.1.18 + rou3: 0.5.1 + set-cookie-parser: 2.7.1 + uncrypto: 0.1.3 + + better-sqlite3@11.9.1: + dependencies: + bindings: 1.5.0 + prebuild-install: 7.1.3 + bidi-js@1.0.3: dependencies: require-from-string: 2.0.2 @@ -18152,6 +18424,10 @@ snapshots: binary-extensions@2.3.0: {} + bindings@1.5.0: + dependencies: + file-uri-to-path: 1.0.0 + bl@4.1.0: dependencies: buffer: 5.7.1 @@ -18814,6 +19090,8 @@ snapshots: has-property-descriptors: 1.0.2 object-keys: 1.1.1 + defu@6.1.4: {} + delaunator@5.0.1: dependencies: robust-predicates: 3.0.2 @@ -19153,7 +19431,7 @@ snapshots: '@typescript-eslint/parser': 5.62.0(eslint@8.57.1)(typescript@5.8.2) eslint: 8.57.1 eslint-import-resolver-node: 0.3.9 - eslint-import-resolver-typescript: 3.10.0(eslint-plugin-import@2.31.0(@typescript-eslint/parser@5.62.0(eslint@8.57.1)(typescript@5.8.2))(eslint@8.57.1))(eslint@8.57.1) + eslint-import-resolver-typescript: 3.10.0(eslint-plugin-import@2.31.0)(eslint@8.57.1) eslint-plugin-import: 2.31.0(@typescript-eslint/parser@5.62.0(eslint@8.57.1)(typescript@5.8.2))(eslint-import-resolver-typescript@3.10.0)(eslint@8.57.1) eslint-plugin-jsx-a11y: 6.10.2(eslint@8.57.1) eslint-plugin-react: 7.37.4(eslint@8.57.1) @@ -19200,7 +19478,7 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-import-resolver-typescript@3.10.0(eslint-plugin-import@2.31.0(@typescript-eslint/parser@5.62.0(eslint@8.57.1)(typescript@5.8.2))(eslint@8.57.1))(eslint@8.57.1): + eslint-import-resolver-typescript@3.10.0(eslint-plugin-import@2.31.0)(eslint@8.57.1): dependencies: '@nolyfill/is-core-module': 1.0.39 debug: 4.4.0 @@ -19215,14 +19493,14 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-module-utils@2.12.0(@typescript-eslint/parser@5.62.0(eslint@8.57.1)(typescript@5.8.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.0(eslint-plugin-import@2.31.0(@typescript-eslint/parser@5.62.0(eslint@8.57.1)(typescript@5.8.2))(eslint@8.57.1))(eslint@8.57.1))(eslint@8.57.1): + eslint-module-utils@2.12.0(@typescript-eslint/parser@5.62.0(eslint@8.57.1)(typescript@5.8.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.0)(eslint@8.57.1): dependencies: debug: 3.2.7 optionalDependencies: '@typescript-eslint/parser': 5.62.0(eslint@8.57.1)(typescript@5.8.2) eslint: 8.57.1 eslint-import-resolver-node: 0.3.9 - eslint-import-resolver-typescript: 3.10.0(eslint-plugin-import@2.31.0(@typescript-eslint/parser@5.62.0(eslint@8.57.1)(typescript@5.8.2))(eslint@8.57.1))(eslint@8.57.1) + eslint-import-resolver-typescript: 3.10.0(eslint-plugin-import@2.31.0)(eslint@8.57.1) transitivePeerDependencies: - supports-color @@ -19245,7 +19523,7 @@ snapshots: doctrine: 2.1.0 eslint: 8.57.1 eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.12.0(@typescript-eslint/parser@5.62.0(eslint@8.57.1)(typescript@5.8.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.0(eslint-plugin-import@2.31.0(@typescript-eslint/parser@5.62.0(eslint@8.57.1)(typescript@5.8.2))(eslint@8.57.1))(eslint@8.57.1))(eslint@8.57.1) + eslint-module-utils: 2.12.0(@typescript-eslint/parser@5.62.0(eslint@8.57.1)(typescript@5.8.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.0)(eslint@8.57.1) hasown: 2.0.2 is-core-module: 2.16.1 is-glob: 4.0.3 @@ -19516,6 +19794,8 @@ snapshots: fast-levenshtein@2.0.6: {} + fast-sha256@1.3.0: {} + fast-uri@3.0.6: {} fast-xml-parser@4.4.1: @@ -19542,6 +19822,8 @@ snapshots: dependencies: flat-cache: 3.2.0 + file-uri-to-path@1.0.0: {} + filelist@1.0.4: dependencies: minimatch: 5.1.6 @@ -20426,7 +20708,7 @@ snapshots: jest-util@29.7.0: dependencies: '@jest/types': 29.6.3 - '@types/node': 20.17.28 + '@types/node': 20.17.30 chalk: 4.1.2 ci-info: 3.9.0 graceful-fs: 4.2.11 @@ -20580,6 +20862,8 @@ snapshots: kleur@4.1.5: {} + kysely@0.27.6: {} + language-subtag-registry@0.3.23: {} language-tags@1.0.9: @@ -21600,6 +21884,8 @@ snapshots: nanoid@5.1.5: {} + nanostores@0.11.4: {} + napi-build-utils@2.0.0: {} natural-compare-lite@1.4.0: {} @@ -22362,6 +22648,12 @@ snapshots: punycode@2.3.1: {} + pvtsutils@1.3.6: + dependencies: + tslib: 2.8.1 + + pvutils@1.1.3: {} + querystringify@2.2.0: {} queue-microtask@1.2.3: {} @@ -22831,6 +23123,8 @@ snapshots: rope-sequence@1.3.4: {} + rou3@0.5.1: {} + rrweb-cssom@0.6.0: {} rrweb-cssom@0.7.1: {} @@ -22961,6 +23255,8 @@ snapshots: set-blocking@2.0.0: optional: true + set-cookie-parser@2.7.1: {} + set-function-length@1.2.2: dependencies: define-data-property: 1.1.4 @@ -23176,6 +23472,11 @@ snapshots: as-table: 1.0.55 get-source: 2.0.12 + standardwebhooks@1.0.0: + dependencies: + '@stablelib/base64': 1.0.1 + fast-sha256: 1.3.0 + std-env@3.8.1: {} stoppable@1.1.0: {} @@ -23590,6 +23891,8 @@ snapshots: has-symbols: 1.1.0 which-boxed-primitive: 1.1.1 + uncrypto@0.1.3: {} + undici-types@6.19.8: {} undici-types@6.20.0: {} From 5975ba9b596d97702607ccdff5eab77382bf48fc Mon Sep 17 00:00:00 2001 From: Nick the Sick Date: Tue, 22 Apr 2025 15:56:33 +0200 Subject: [PATCH 02/16] chore: hoist prettier to top-level --- docs/package.json | 3 +- docs/prettier.config.js | 7 -- package.json | 2 + packages/ariakit/package.json | 1 - packages/code-block/package.json | 1 - packages/core/package.json | 1 - packages/dev-scripts/package.json | 1 - packages/mantine/package.json | 1 - packages/react/package.json | 1 - packages/server-util/package.json | 1 - packages/shadcn/package.json | 1 - packages/xl-docx-exporter/package.json | 1 - packages/xl-multi-column/package.json | 1 - packages/xl-odt-exporter/package.json | 1 - packages/xl-pdf-exporter/package.json | 1 - pnpm-lock.yaml | 109 ++++++++++++------------- prettier.config.js | 1 + 17 files changed, 56 insertions(+), 78 deletions(-) delete mode 100644 docs/prettier.config.js diff --git a/docs/package.json b/docs/package.json index 420b02f74a..27fa0123ea 100644 --- a/docs/package.json +++ b/docs/package.json @@ -25,6 +25,7 @@ "@polar-sh/sdk": "0.32.10", "@sentry/nextjs": "9.4.0", "@types/better-sqlite3": "7.6.13", + "@types/nodemailer": "6.4.17", "@vercel/analytics": "^1.2.2", "@vercel/og": "^0.6.2", "better-auth": "1.2.7", @@ -36,6 +37,7 @@ "next-auth": "^5.0.0-beta.19", "nextra": "^2.13.2", "nextra-theme-docs": "^2.13.2", + "nodemailer": "6.10.1", "partykit": "^0.0.84", "raw-loader": "^4.0.2", "react": "^18.3.1", @@ -54,7 +56,6 @@ "eslint": "^8", "eslint-config-next": "14.1.0", "postcss": "^8", - "prettier-plugin-tailwindcss": "^0.5.11", "tailwindcss": "^3.3.0", "typescript": "^5" } diff --git a/docs/prettier.config.js b/docs/prettier.config.js deleted file mode 100644 index 64cfdbc5d1..0000000000 --- a/docs/prettier.config.js +++ /dev/null @@ -1,7 +0,0 @@ -module.exports = { - $schema: "http://json.schemastore.org/prettierrc", - tabWidth: 2, - printWidth: 80, - jsxBracketSameLine: true, - plugins: ["prettier-plugin-tailwindcss"] -}; diff --git a/package.json b/package.json index 9f8c9ba0ec..e7f83a9a7c 100644 --- a/package.json +++ b/package.json @@ -9,6 +9,8 @@ "eslint-plugin-import": "^2.31.0", "glob": "^10.3.10", "nx": "20.6.4", + "prettier": "3.5.3", + "prettier-plugin-tailwindcss": "0.6.11", "serve": "14.2.4", "typescript": "^5.3.3", "vitest": "^2.0.3", diff --git a/packages/ariakit/package.json b/packages/ariakit/package.json index 1a94994ac4..030f5b2b49 100644 --- a/packages/ariakit/package.json +++ b/packages/ariakit/package.json @@ -64,7 +64,6 @@ "@types/react-dom": "^18.0.9", "@vitejs/plugin-react": "^4.3.1", "eslint": "^8.10.0", - "prettier": "^2.7.1", "rimraf": "^5.0.5", "rollup-plugin-webpack-stats": "^0.2.2", "typescript": "^5.3.3", diff --git a/packages/code-block/package.json b/packages/code-block/package.json index 3a81dbab5c..6361035d67 100644 --- a/packages/code-block/package.json +++ b/packages/code-block/package.json @@ -59,7 +59,6 @@ }, "devDependencies": { "eslint": "^8.10.0", - "prettier": "^2.7.1", "rollup-plugin-webpack-stats": "^0.2.2", "typescript": "^5.0.4", "vite": "^5.3.4", diff --git a/packages/core/package.json b/packages/core/package.json index a4311e89ef..c9f0839a55 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -121,7 +121,6 @@ "@types/uuid": "^8.3.4", "eslint": "^8.10.0", "jsdom": "^25.0.1", - "prettier": "^2.7.1", "rimraf": "^5.0.5", "rollup-plugin-webpack-stats": "^0.2.2", "typescript": "^5.3.3", diff --git a/packages/dev-scripts/package.json b/packages/dev-scripts/package.json index e810282178..3f9a5e8d51 100644 --- a/packages/dev-scripts/package.json +++ b/packages/dev-scripts/package.json @@ -23,7 +23,6 @@ "@types/react-dom": "^18.0.9", "eslint": "^8.10.0", "glob": "^10.3.10", - "prettier": "^2.7.1", "react": "^18.3.1", "react-dom": "^18.3.1", "tinyglobby": "0.2.12", diff --git a/packages/mantine/package.json b/packages/mantine/package.json index fd08ffe6b9..bc9fbc2fbc 100644 --- a/packages/mantine/package.json +++ b/packages/mantine/package.json @@ -67,7 +67,6 @@ "@types/react-dom": "^18.0.9", "@vitejs/plugin-react": "^4.3.1", "eslint": "^8.10.0", - "prettier": "^2.7.1", "rimraf": "^5.0.5", "rollup-plugin-webpack-stats": "^0.2.2", "typescript": "^5.3.3", diff --git a/packages/react/package.json b/packages/react/package.json index 4c77f9ce22..e154caa9f9 100644 --- a/packages/react/package.json +++ b/packages/react/package.json @@ -76,7 +76,6 @@ "@types/react-dom": "^18.0.9", "@vitejs/plugin-react": "^4.3.1", "eslint": "^8.10.0", - "prettier": "^2.7.1", "react": "^18.3.1", "react-dom": "^18.3.1", "rimraf": "^5.0.5", diff --git a/packages/server-util/package.json b/packages/server-util/package.json index 10853fd895..ce3b5e3316 100644 --- a/packages/server-util/package.json +++ b/packages/server-util/package.json @@ -69,7 +69,6 @@ "@types/react": "^18.0.25", "@types/react-dom": "^18.0.9", "eslint": "^8.10.0", - "prettier": "^2.7.1", "rollup-plugin-webpack-stats": "^0.2.2", "typescript": "^5.0.4", "vite": "^5.3.4", diff --git a/packages/shadcn/package.json b/packages/shadcn/package.json index 37cd2cc86a..3454eec888 100644 --- a/packages/shadcn/package.json +++ b/packages/shadcn/package.json @@ -85,7 +85,6 @@ "@types/react-dom": "^18.0.9", "@vitejs/plugin-react": "^4.3.1", "eslint": "^8.10.0", - "prettier": "^2.7.1", "rimraf": "^5.0.5", "rollup-plugin-webpack-stats": "^0.2.2", "typescript": "^5.3.3", diff --git a/packages/xl-docx-exporter/package.json b/packages/xl-docx-exporter/package.json index f14007e272..784e32441b 100644 --- a/packages/xl-docx-exporter/package.json +++ b/packages/xl-docx-exporter/package.json @@ -66,7 +66,6 @@ "@types/react-dom": "^18.0.9", "@zip.js/zip.js": "^2.7.57", "eslint": "^8.10.0", - "prettier": "^2.7.1", "rollup-plugin-webpack-stats": "^0.2.2", "typescript": "^5.0.4", "vite": "^5.3.4", diff --git a/packages/xl-multi-column/package.json b/packages/xl-multi-column/package.json index 94443ce77c..a711a6252a 100644 --- a/packages/xl-multi-column/package.json +++ b/packages/xl-multi-column/package.json @@ -67,7 +67,6 @@ "@vitest/ui": "^2.1.4", "eslint": "^8.10.0", "jsdom": "^21.1.0", - "prettier": "^2.7.1", "rimraf": "^5.0.5", "rollup-plugin-webpack-stats": "^0.2.2", "typescript": "^5.3.3", diff --git a/packages/xl-odt-exporter/package.json b/packages/xl-odt-exporter/package.json index 58d2b617ab..3083653382 100644 --- a/packages/xl-odt-exporter/package.json +++ b/packages/xl-odt-exporter/package.json @@ -65,7 +65,6 @@ "@testing-library/react": "^16.0.1", "@types/react": "^18.0.25", "@types/react-dom": "^18.0.9", - "prettier": "^2.7.1", "rollup-plugin-webpack-stats": "^0.2.2", "typescript": "^5.0.4", "vite": "^5.3.4", diff --git a/packages/xl-pdf-exporter/package.json b/packages/xl-pdf-exporter/package.json index a73d927887..783fc077f2 100644 --- a/packages/xl-pdf-exporter/package.json +++ b/packages/xl-pdf-exporter/package.json @@ -70,7 +70,6 @@ "eslint": "^8.10.0", "jest-image-snapshot": "^6.4.0", "pdf-to-img": "^4.2.0", - "prettier": "^2.7.1", "react-element-to-jsx-string": "^15.0.0", "rollup-plugin-webpack-stats": "^0.2.2", "typescript": "^5.0.4", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index b559c56a90..f8387dc6ce 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -35,6 +35,12 @@ importers: nx: specifier: 20.6.4 version: 20.6.4 + prettier: + specifier: 3.5.3 + version: 3.5.3 + prettier-plugin-tailwindcss: + specifier: 0.6.11 + version: 0.6.11(prettier@3.5.3) serve: specifier: 14.2.4 version: 14.2.4 @@ -98,6 +104,9 @@ importers: '@types/better-sqlite3': specifier: 7.6.13 version: 7.6.13 + '@types/nodemailer': + specifier: 6.4.17 + version: 6.4.17 '@vercel/analytics': specifier: ^1.2.2 version: 1.5.0(next@15.2.4(@babel/core@7.26.10)(@opentelemetry/api@1.9.0)(@playwright/test@1.51.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1) @@ -124,13 +133,16 @@ importers: version: 15.2.4(@babel/core@7.26.10)(@opentelemetry/api@1.9.0)(@playwright/test@1.51.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) next-auth: specifier: ^5.0.0-beta.19 - version: 5.0.0-beta.25(next@15.2.4(@babel/core@7.26.10)(@opentelemetry/api@1.9.0)(@playwright/test@1.51.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1) + version: 5.0.0-beta.25(next@15.2.4(@babel/core@7.26.10)(@opentelemetry/api@1.9.0)(@playwright/test@1.51.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(nodemailer@6.10.1)(react@18.3.1) nextra: specifier: ^2.13.2 version: 2.13.4(next@15.2.4(@babel/core@7.26.10)(@opentelemetry/api@1.9.0)(@playwright/test@1.51.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1) nextra-theme-docs: specifier: ^2.13.2 version: 2.13.4(next@15.2.4(@babel/core@7.26.10)(@opentelemetry/api@1.9.0)(@playwright/test@1.51.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(nextra@2.13.4(next@15.2.4(@babel/core@7.26.10)(@opentelemetry/api@1.9.0)(@playwright/test@1.51.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + nodemailer: + specifier: 6.10.1 + version: 6.10.1 partykit: specifier: ^0.0.84 version: 0.0.84 @@ -180,9 +192,6 @@ importers: postcss: specifier: ^8 version: 8.5.3 - prettier-plugin-tailwindcss: - specifier: ^0.5.11 - version: 0.5.14(prettier@2.8.8) tailwindcss: specifier: ^3.3.0 version: 3.4.17 @@ -2799,9 +2808,6 @@ importers: eslint: specifier: ^8.10.0 version: 8.57.1 - prettier: - specifier: ^2.7.1 - version: 2.8.8 rimraf: specifier: ^5.0.5 version: 5.0.10 @@ -2848,9 +2854,6 @@ importers: eslint: specifier: ^8.10.0 version: 8.57.1 - prettier: - specifier: ^2.7.1 - version: 2.8.8 rollup-plugin-webpack-stats: specifier: ^0.2.2 version: 0.2.6(rollup@4.37.0) @@ -3014,9 +3017,6 @@ importers: jsdom: specifier: ^25.0.1 version: 25.0.1(canvas@2.11.2(encoding@0.1.13)) - prettier: - specifier: ^2.7.1 - version: 2.8.8 rimraf: specifier: ^5.0.5 version: 5.0.10 @@ -3050,9 +3050,6 @@ importers: glob: specifier: ^10.3.10 version: 10.4.5 - prettier: - specifier: ^2.7.1 - version: 2.8.8 react: specifier: ^18.3.1 version: 18.3.1 @@ -3108,9 +3105,6 @@ importers: eslint: specifier: ^8.10.0 version: 8.57.1 - prettier: - specifier: ^2.7.1 - version: 2.8.8 rimraf: specifier: ^5.0.5 version: 5.0.10 @@ -3184,9 +3178,6 @@ importers: eslint: specifier: ^8.10.0 version: 8.57.1 - prettier: - specifier: ^2.7.1 - version: 2.8.8 react: specifier: ^18.3.1 version: 18.3.1 @@ -3260,9 +3251,6 @@ importers: eslint: specifier: ^8.10.0 version: 8.57.1 - prettier: - specifier: ^2.7.1 - version: 2.8.8 rollup-plugin-webpack-stats: specifier: ^0.2.2 version: 0.2.6(rollup@4.37.0) @@ -3372,9 +3360,6 @@ importers: eslint: specifier: ^8.10.0 version: 8.57.1 - prettier: - specifier: ^2.7.1 - version: 2.8.8 rimraf: specifier: ^5.0.5 version: 5.0.10 @@ -3421,9 +3406,6 @@ importers: eslint: specifier: ^8.10.0 version: 8.57.1 - prettier: - specifier: ^2.7.1 - version: 2.8.8 react: specifier: ^18.3.1 version: 18.3.1 @@ -3494,9 +3476,6 @@ importers: jsdom: specifier: ^21.1.0 version: 21.1.2(canvas@2.11.2(encoding@0.1.13)) - prettier: - specifier: ^2.7.1 - version: 2.8.8 react: specifier: ^18.3.1 version: 18.3.1 @@ -3546,9 +3525,6 @@ importers: '@types/react-dom': specifier: ^18.0.9 version: 18.3.5(@types/react@18.3.20) - prettier: - specifier: ^2.7.1 - version: 2.8.8 react: specifier: ^18.3.1 version: 18.3.1 @@ -3616,9 +3592,6 @@ importers: pdf-to-img: specifier: ^4.2.0 version: 4.4.0(encoding@0.1.13) - prettier: - specifier: ^2.7.1 - version: 2.8.8 react: specifier: ^18.3.1 version: 18.3.1 @@ -7498,6 +7471,9 @@ packages: '@types/node@22.13.13': resolution: {integrity: sha512-ClsL5nMwKaBRwPcCvH8E7+nU4GxHVx1axNvMZTFHMEfNI7oahimt26P5zjVCRrjiIWj6YFXfE1v3dEp94wLcGQ==} + '@types/nodemailer@6.4.17': + resolution: {integrity: sha512-I9CCaIp6DTldEg7vyUTZi8+9Vo0hi1/T8gv3C89yk1rSAAzoKQ8H8ki/jBYJSFoH/BisgLP8tkZMlQ91CIquww==} + '@types/parse-json@4.0.2': resolution: {integrity: sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==} @@ -10978,6 +10954,10 @@ packages: node-releases@2.0.19: resolution: {integrity: sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==} + nodemailer@6.10.1: + resolution: {integrity: sha512-Z+iLaBGVaSjbIzQ4pX6XV41HrooLsQ10ZWPUehGmuantvzWoDVBnmsdUcOIDM1t+yPor5pDhVlDESgOMEGxhHA==} + engines: {node: '>=6.0.0'} + non-layered-tidy-tree-layout@2.0.2: resolution: {integrity: sha512-gkXMxRzUH+PB0ax9dUN0yYF0S25BqeAYqhgMaLUFmpXLEk7Fcu8f4emJuOAY0V8kjDICxROIKsTAKsV/v355xw==} @@ -11382,21 +11362,22 @@ packages: resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} engines: {node: '>= 0.8.0'} - prettier-plugin-tailwindcss@0.5.14: - resolution: {integrity: sha512-Puaz+wPUAhFp8Lo9HuciYKM2Y2XExESjeT+9NQoVFXZsPPnc9VYss2SpxdQ6vbatmt8/4+SN0oe0I1cPDABg9Q==} + prettier-plugin-tailwindcss@0.6.11: + resolution: {integrity: sha512-YxaYSIvZPAqhrrEpRtonnrXdghZg1irNg4qrjboCXrpybLWVs55cW2N3juhspVJiO0JBvYJT8SYsJpc8OQSnsA==} engines: {node: '>=14.21.3'} peerDependencies: '@ianvs/prettier-plugin-sort-imports': '*' '@prettier/plugin-pug': '*' '@shopify/prettier-plugin-liquid': '*' '@trivago/prettier-plugin-sort-imports': '*' - '@zackad/prettier-plugin-twig-melody': '*' + '@zackad/prettier-plugin-twig': '*' prettier: ^3.0 prettier-plugin-astro: '*' prettier-plugin-css-order: '*' prettier-plugin-import-sort: '*' prettier-plugin-jsdoc: '*' prettier-plugin-marko: '*' + prettier-plugin-multiline-arrays: '*' prettier-plugin-organize-attributes: '*' prettier-plugin-organize-imports: '*' prettier-plugin-sort-imports: '*' @@ -11411,7 +11392,7 @@ packages: optional: true '@trivago/prettier-plugin-sort-imports': optional: true - '@zackad/prettier-plugin-twig-melody': + '@zackad/prettier-plugin-twig': optional: true prettier-plugin-astro: optional: true @@ -11423,6 +11404,8 @@ packages: optional: true prettier-plugin-marko: optional: true + prettier-plugin-multiline-arrays: + optional: true prettier-plugin-organize-attributes: optional: true prettier-plugin-organize-imports: @@ -11434,9 +11417,9 @@ packages: prettier-plugin-svelte: optional: true - prettier@2.8.8: - resolution: {integrity: sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==} - engines: {node: '>=10.13.0'} + prettier@3.5.3: + resolution: {integrity: sha512-QQtaxnoDJeAkDvDKWCLiwIXkTgRhwYDEQCghU9Z6q03iyek/rxRh/2lC3HB7P8sWT2xC/y5JDctPLBIGzHKbhw==} + engines: {node: '>=14'} hasBin: true pretty-format@27.5.1: @@ -13239,7 +13222,7 @@ snapshots: '@csstools/css-tokenizer': 3.0.3 lru-cache: 10.4.3 - '@auth/core@0.37.2': + '@auth/core@0.37.2(nodemailer@6.10.1)': dependencies: '@panva/hkdf': 1.2.1 '@types/cookie': 0.6.0 @@ -13248,6 +13231,8 @@ snapshots: oauth4webapi: 3.3.1 preact: 10.11.3 preact-render-to-string: 5.2.3(preact@10.11.3) + optionalDependencies: + nodemailer: 6.10.1 '@aws-crypto/crc32@5.2.0': dependencies: @@ -17523,6 +17508,10 @@ snapshots: dependencies: undici-types: 6.20.0 + '@types/nodemailer@6.4.17': + dependencies: + '@types/node': 20.17.30 + '@types/parse-json@4.0.2': {} '@types/pg-pool@2.0.6': @@ -19431,7 +19420,7 @@ snapshots: '@typescript-eslint/parser': 5.62.0(eslint@8.57.1)(typescript@5.8.2) eslint: 8.57.1 eslint-import-resolver-node: 0.3.9 - eslint-import-resolver-typescript: 3.10.0(eslint-plugin-import@2.31.0)(eslint@8.57.1) + eslint-import-resolver-typescript: 3.10.0(eslint-plugin-import@2.31.0(@typescript-eslint/parser@5.62.0(eslint@8.57.1)(typescript@5.8.2))(eslint@8.57.1))(eslint@8.57.1) eslint-plugin-import: 2.31.0(@typescript-eslint/parser@5.62.0(eslint@8.57.1)(typescript@5.8.2))(eslint-import-resolver-typescript@3.10.0)(eslint@8.57.1) eslint-plugin-jsx-a11y: 6.10.2(eslint@8.57.1) eslint-plugin-react: 7.37.4(eslint@8.57.1) @@ -19478,7 +19467,7 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-import-resolver-typescript@3.10.0(eslint-plugin-import@2.31.0)(eslint@8.57.1): + eslint-import-resolver-typescript@3.10.0(eslint-plugin-import@2.31.0(@typescript-eslint/parser@5.62.0(eslint@8.57.1)(typescript@5.8.2))(eslint@8.57.1))(eslint@8.57.1): dependencies: '@nolyfill/is-core-module': 1.0.39 debug: 4.4.0 @@ -19493,14 +19482,14 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-module-utils@2.12.0(@typescript-eslint/parser@5.62.0(eslint@8.57.1)(typescript@5.8.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.0)(eslint@8.57.1): + eslint-module-utils@2.12.0(@typescript-eslint/parser@5.62.0(eslint@8.57.1)(typescript@5.8.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.0(eslint-plugin-import@2.31.0(@typescript-eslint/parser@5.62.0(eslint@8.57.1)(typescript@5.8.2))(eslint@8.57.1))(eslint@8.57.1))(eslint@8.57.1): dependencies: debug: 3.2.7 optionalDependencies: '@typescript-eslint/parser': 5.62.0(eslint@8.57.1)(typescript@5.8.2) eslint: 8.57.1 eslint-import-resolver-node: 0.3.9 - eslint-import-resolver-typescript: 3.10.0(eslint-plugin-import@2.31.0)(eslint@8.57.1) + eslint-import-resolver-typescript: 3.10.0(eslint-plugin-import@2.31.0(@typescript-eslint/parser@5.62.0(eslint@8.57.1)(typescript@5.8.2))(eslint@8.57.1))(eslint@8.57.1) transitivePeerDependencies: - supports-color @@ -19523,7 +19512,7 @@ snapshots: doctrine: 2.1.0 eslint: 8.57.1 eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.12.0(@typescript-eslint/parser@5.62.0(eslint@8.57.1)(typescript@5.8.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.0)(eslint@8.57.1) + eslint-module-utils: 2.12.0(@typescript-eslint/parser@5.62.0(eslint@8.57.1)(typescript@5.8.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.0(eslint-plugin-import@2.31.0(@typescript-eslint/parser@5.62.0(eslint@8.57.1)(typescript@5.8.2))(eslint@8.57.1))(eslint@8.57.1))(eslint@8.57.1) hasown: 2.0.2 is-core-module: 2.16.1 is-glob: 4.0.3 @@ -21896,11 +21885,13 @@ snapshots: neo-async@2.6.2: {} - next-auth@5.0.0-beta.25(next@15.2.4(@babel/core@7.26.10)(@opentelemetry/api@1.9.0)(@playwright/test@1.51.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1): + next-auth@5.0.0-beta.25(next@15.2.4(@babel/core@7.26.10)(@opentelemetry/api@1.9.0)(@playwright/test@1.51.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(nodemailer@6.10.1)(react@18.3.1): dependencies: - '@auth/core': 0.37.2 + '@auth/core': 0.37.2(nodemailer@6.10.1) next: 15.2.4(@babel/core@7.26.10)(@opentelemetry/api@1.9.0)(@playwright/test@1.51.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) react: 18.3.1 + optionalDependencies: + nodemailer: 6.10.1 next-mdx-remote@4.4.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1): dependencies: @@ -22022,6 +22013,8 @@ snapshots: node-releases@2.0.19: {} + nodemailer@6.10.1: {} + non-layered-tidy-tree-layout@2.0.2: {} nopt@5.0.0: @@ -22479,11 +22472,11 @@ snapshots: prelude-ls@1.2.1: {} - prettier-plugin-tailwindcss@0.5.14(prettier@2.8.8): + prettier-plugin-tailwindcss@0.6.11(prettier@3.5.3): dependencies: - prettier: 2.8.8 + prettier: 3.5.3 - prettier@2.8.8: {} + prettier@3.5.3: {} pretty-format@27.5.1: dependencies: diff --git a/prettier.config.js b/prettier.config.js index add9f85b15..273f1e5c09 100644 --- a/prettier.config.js +++ b/prettier.config.js @@ -3,4 +3,5 @@ module.exports = { tabWidth: 2, printWidth: 80, jsxBracketSameLine: true, + plugins: ["prettier-plugin-tailwindcss"], }; From af103ad071a916159f40e9ce0d3440824292c642 Mon Sep 17 00:00:00 2001 From: Nick the Sick Date: Tue, 22 Apr 2025 15:59:27 +0200 Subject: [PATCH 03/16] chore: fix generation --- packages/dev-scripts/examples/gen.ts | 10 +++++----- packages/dev-scripts/package.json | 3 +++ pnpm-lock.yaml | 4 ++++ 3 files changed, 12 insertions(+), 5 deletions(-) diff --git a/packages/dev-scripts/examples/gen.ts b/packages/dev-scripts/examples/gen.ts index c14fcfca14..e0e600cdc9 100644 --- a/packages/dev-scripts/examples/gen.ts +++ b/packages/dev-scripts/examples/gen.ts @@ -33,7 +33,7 @@ async function writeTemplate(project: Project, templateFile: string) { const targetFilePath = path.join( "../../", project.pathFromRoot, - path.basename(templateFile).replace(".template.tsx", "") + path.basename(templateFile).replace(".template.tsx", ""), ); let stringOutput: string | undefined = undefined; @@ -41,10 +41,10 @@ async function writeTemplate(project: Project, templateFile: string) { stringOutput = ReactDOM.renderToString(ret); const prettierConfig = await prettier.resolveConfig(targetFilePath); - stringOutput = prettier.format(stringOutput, { + stringOutput = await prettier.format(stringOutput, { ...prettierConfig, parser: "html", - }) as string; + }); } else if (typeof ret === "string") { stringOutput = ret; } else if (typeof ret === "object") { @@ -58,7 +58,7 @@ async function writeTemplate(project: Project, templateFile: string) { async function generateCodeForExample(project: Project) { const templates = glob.sync( - replacePathSepToSlash(path.resolve(dir, "./template-react/*.template.tsx")) + replacePathSepToSlash(path.resolve(dir, "./template-react/*.template.tsx")), ); for (const template of templates) { @@ -90,5 +90,5 @@ for (const project of projects) { } await generateExamplesData( - projects.filter((p) => p.config?.playground === true) + projects.filter((p) => p.config?.playground === true), ); diff --git a/packages/dev-scripts/package.json b/packages/dev-scripts/package.json index 3f9a5e8d51..0b997a7ffc 100644 --- a/packages/dev-scripts/package.json +++ b/packages/dev-scripts/package.json @@ -33,5 +33,8 @@ "extends": [ "../../.eslintrc.js" ] + }, + "dependencies": { + "prettier": "3.5.3" } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index f8387dc6ce..81450f204e 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -3037,6 +3037,10 @@ importers: version: 2.1.9(@types/node@22.13.13)(@vitest/ui@2.1.9)(jsdom@25.0.1(canvas@2.11.2(encoding@0.1.13)))(terser@5.39.0) packages/dev-scripts: + dependencies: + prettier: + specifier: 3.5.3 + version: 3.5.3 devDependencies: '@types/react': specifier: ^18.0.25 From 284d550fe167f79300e29a040a8dedab8b1af671 Mon Sep 17 00:00:00 2001 From: Nick the Sick Date: Tue, 22 Apr 2025 19:29:48 +0200 Subject: [PATCH 04/16] feat: implement email notifications and magic links --- docs/.env.local.example | 18 +- docs/app/signup/page.tsx | 19 +- docs/auth.ts | 138 +-- docs/emails/magic-link.tsx | 97 ++ docs/emails/reset-password.tsx | 94 ++ docs/emails/verify-email.tsx | 94 ++ docs/package.json | 11 +- docs/theme.config.tsx | 6 +- docs/util/auth-client.ts | 12 +- docs/util/send-mail.tsx | 86 ++ package.json | 2 +- pnpm-lock.yaml | 1552 +++++++++++++++++++++++++++----- 12 files changed, 1837 insertions(+), 292 deletions(-) create mode 100644 docs/emails/magic-link.tsx create mode 100644 docs/emails/reset-password.tsx create mode 100644 docs/emails/verify-email.tsx create mode 100644 docs/util/send-mail.tsx diff --git a/docs/.env.local.example b/docs/.env.local.example index 50ec3e8011..e9dcc0e453 100644 --- a/docs/.env.local.example +++ b/docs/.env.local.example @@ -1,8 +1,22 @@ -AUTH_SECRET= # Linux: `openssl rand -hex 32` or go to https://generate-secret.vercel.app/32 - AUTH_GITHUB_ID= AUTH_GITHUB_SECRET= # The SENTRY_AUTH_TOKEN variable is picked up by the Sentry Build Plugin. # It's used for authentication when uploading source maps. SENTRY_AUTH_TOKEN= + +#Email +SMTP_HOST= +SMTP_USER= +SMTP_PASS= +SMTP_PORT= +# Insecure if false, secure if any other value +SMTP_SECURE=false + +# Better Auth +BETTER_AUTH_SECRET= # Linux: `openssl rand -hex 32` or go to https://generate-secret.vercel.app/32 +BETTER_AUTH_URL=http://localhost:3000 + +# Polar +POLAR_ACCESS_TOKEN= +POLAR_WEBHOOK_SECRET= diff --git a/docs/app/signup/page.tsx b/docs/app/signup/page.tsx index 1ec8a359c6..66f741e183 100644 --- a/docs/app/signup/page.tsx +++ b/docs/app/signup/page.tsx @@ -1,6 +1,6 @@ "use client"; -import { signUp } from "@/util/auth-client"; +import { signIn, signUp } from "@/util/auth-client"; import { useState } from "react"; // TODO Do we want email & password signin? or just social? @@ -19,7 +19,6 @@ export default function Register() { return (
-

Register

Register +
); -}; \ No newline at end of file +} diff --git a/docs/auth.ts b/docs/auth.ts index fc072c8746..63b3701a28 100644 --- a/docs/auth.ts +++ b/docs/auth.ts @@ -1,65 +1,93 @@ -import { betterAuth } from "better-auth"; -import Database from "better-sqlite3"; import { polar } from "@polar-sh/better-auth"; import { Polar } from "@polar-sh/sdk"; -import { openAPI } from "better-auth/plugins" +import { betterAuth } from "better-auth"; +import { magicLink, openAPI } from "better-auth/plugins"; +import Database from "better-sqlite3"; + +import { sendEmail } from "./util/send-mail"; export const client = new Polar({ - accessToken: process.env.POLAR_ACCESS_TOKEN, - // Use 'sandbox' if you're using the Polar Sandbox environment - // Remember that access tokens, products, etc. are completely separated between environments. - // Access tokens obtained in Production are for instance not usable in the Sandbox environment. - server: 'sandbox' + accessToken: process.env.POLAR_ACCESS_TOKEN, + // Use 'sandbox' if you're using the Polar Sandbox environment + // Remember that access tokens, products, etc. are completely separated between environments. + // Access tokens obtained in Production are for instance not usable in the Sandbox environment. + server: "sandbox", }); export const auth = betterAuth({ - emailAndPassword: { - enabled: true + emailVerification: { + async sendVerificationEmail({ user, url }) { + await sendEmail({ + to: user.email, + template: "verifyEmail", + props: { url }, + }); + }, + }, + emailAndPassword: { + enabled: true, + requireEmailVerification: true, + async sendResetPassword(data) { + await sendEmail({ + to: data.user.email, + template: "resetPassword", + props: { url: data.url }, + }); + }, }, - socialProviders: { - github: { - clientId: process.env.AUTH_GITHUB_ID as string, - clientSecret: process.env.AUTH_GITHUB_SECRET as string - }, + socialProviders: { + github: { + clientId: process.env.AUTH_GITHUB_ID as string, + clientSecret: process.env.AUTH_GITHUB_SECRET as string, + }, }, database: new Database("./sqlite.db"), - plugins: [ - // Just temporary for testing - // Serves on http://localhost:3000/api/auth/reference - openAPI(), - polar({ - client, - // Enable automatic Polar Customer creation on signup - createCustomerOnSignUp: true, - // http://localhost:3000/api/auth/portal - enableCustomerPortal: true, - // Configure checkout - checkout: { - enabled: true, - products: [ - { - productId: "8049f66f-fd0a-4690-a0aa-442ac5b03040", // ID of Product from Polar Dashboard - slug: "business" // Custom slug for easy reference in Checkout URL, e.g. /checkout/pro - // http://localhost:3000/api/auth/checkout/business - }, - { - productId: 'ab70fea5-172c-4aac-b3fc-0824f2a5b670', - slug: 'starter' - // http://localhost:3000/api/auth/checkout/starter - } - ], - // TODO set to actual page (welcome screen) - successUrl: "/success?checkout_id={CHECKOUT_ID}" - }, - // Incoming Webhooks handler will be installed at /polar/webhooks - webhooks: { - // webhooks have to be publicly accessible - // ngrok http http://localhost:3000 - secret: process.env.POLAR_WEBHOOK_SECRET as string, - onPayload: async (payload) => { - console.log(payload) - }, - } - }) - ] -}); \ No newline at end of file + plugins: [ + magicLink({ + sendMagicLink: async ({ email, url }) => { + await sendEmail({ + to: email, + template: "magicLink", + props: { url }, + }); + }, + }), + // Just temporary for testing + // Serves on http://localhost:3000/api/auth/reference + openAPI(), + polar({ + client, + // Enable automatic Polar Customer creation on signup + createCustomerOnSignUp: true, + // http://localhost:3000/api/auth/portal + enableCustomerPortal: true, + // Configure checkout + checkout: { + enabled: true, + products: [ + { + productId: "8049f66f-fd0a-4690-a0aa-442ac5b03040", // ID of Product from Polar Dashboard + slug: "business", // Custom slug for easy reference in Checkout URL, e.g. /checkout/pro + // http://localhost:3000/api/auth/checkout/business + }, + { + productId: "ab70fea5-172c-4aac-b3fc-0824f2a5b670", + slug: "starter", + // http://localhost:3000/api/auth/checkout/starter + }, + ], + // TODO set to actual page (welcome screen) + successUrl: "/success?checkout_id={CHECKOUT_ID}", + }, + // Incoming Webhooks handler will be installed at /polar/webhooks + webhooks: { + // webhooks have to be publicly accessible + // ngrok http http://localhost:3000 + secret: process.env.POLAR_WEBHOOK_SECRET as string, + onPayload: async (payload) => { + console.log(payload); + }, + }, + }), + ], +}); diff --git a/docs/emails/magic-link.tsx b/docs/emails/magic-link.tsx new file mode 100644 index 0000000000..747a7d0df2 --- /dev/null +++ b/docs/emails/magic-link.tsx @@ -0,0 +1,97 @@ +import { + Body, + Button, + Container, + Head, + Html, + Img, + Preview, + Section, + Text, +} from "@react-email/components"; + +export interface MagicLinkEmailProps { + name?: string; + url?: string; +} + +export const MagicLinkEmail = ({ name, url }: MagicLinkEmailProps) => { + return ( + + + + BlockNote - Sign in to your account + + BlockNote +
+ Hi{name ? ` ${name}` : ""}, + + Someone recently requested a magic link for your BlockNote + account. If this was you, you can sign in here: + + + + If you don't want to sign in or didn't request this, + just ignore and delete this message. + + + To keep your account secure, please don't forward this email + to anyone. + +
+
+ + + ); +}; + +MagicLinkEmail.PreviewProps = { + name: "", + url: "https://blocknotejs.org", +} as MagicLinkEmailProps; + +export default MagicLinkEmail; + +const main = { + backgroundColor: "#f6f9fc", + padding: "10px 0", +}; + +const container = { + backgroundColor: "#ffffff", + border: "1px solid #f0f0f0", + padding: "45px", +}; + +const text = { + fontSize: "16px", + fontFamily: + "'Open Sans', 'HelveticaNeue-Light', 'Helvetica Neue Light', 'Helvetica Neue', Helvetica, Arial, 'Lucida Grande', sans-serif", + fontWeight: "300", + color: "#404040", + lineHeight: "26px", +}; + +const button = { + backgroundColor: "#007ee6", + borderRadius: "4px", + color: "#fff", + fontFamily: "'Open Sans', 'Helvetica Neue', Arial", + fontSize: "15px", + textDecoration: "none", + textAlign: "center" as const, + display: "block", + width: "210px", + padding: "14px 7px", +}; + +const anchor = { + textDecoration: "underline", +}; diff --git a/docs/emails/reset-password.tsx b/docs/emails/reset-password.tsx new file mode 100644 index 0000000000..a98175e2d3 --- /dev/null +++ b/docs/emails/reset-password.tsx @@ -0,0 +1,94 @@ +import { + Body, + Button, + Container, + Head, + Html, + Img, + Preview, + Section, + Text, +} from "@react-email/components"; + +export interface ResetPasswordProps { + name?: string; + url?: string; +} + +export const ResetPassword = ({ name, url }: ResetPasswordProps) => { + return ( + + + + BlockNote - Reset your password + + BlockNote +
+ Hi{name ? ` ${name}` : ""}, + + Someone recently requested a password reset for your BlockNote + account. If this was you, you can reset your password by clicking + the button below: + + + + If you didn't request a password reset, you can safely ignore + this email. + + + To keep your account secure, please don't forward this email + to anyone. + +
+
+ + + ); +}; + +ResetPassword.PreviewProps = { + name: "", + url: "https://blocknotejs.org", +} as ResetPasswordProps; + +export default ResetPassword; + +const main = { + backgroundColor: "#f6f9fc", + padding: "10px 0", +}; + +const container = { + backgroundColor: "#ffffff", + border: "1px solid #f0f0f0", + padding: "45px", +}; + +const text = { + fontSize: "16px", + fontFamily: + "'Open Sans', 'HelveticaNeue-Light', 'Helvetica Neue Light', 'Helvetica Neue', Helvetica, Arial, 'Lucida Grande', sans-serif", + fontWeight: "300", + color: "#404040", + lineHeight: "26px", +}; + +const button = { + backgroundColor: "#007ee6", + borderRadius: "4px", + color: "#fff", + fontFamily: "'Open Sans', 'Helvetica Neue', Arial", + fontSize: "15px", + textDecoration: "none", + textAlign: "center" as const, + display: "block", + width: "210px", + padding: "14px 7px", +}; diff --git a/docs/emails/verify-email.tsx b/docs/emails/verify-email.tsx new file mode 100644 index 0000000000..b6d8be7954 --- /dev/null +++ b/docs/emails/verify-email.tsx @@ -0,0 +1,94 @@ +import { + Body, + Button, + Container, + Head, + Html, + Img, + Preview, + Section, + Text, +} from "@react-email/components"; + +export interface VerifyEmailProps { + name?: string; + url?: string; +} + +export const VerifyEmail = ({ name, url }: VerifyEmailProps) => { + return ( + + + + BlockNote - Verify your email address + + BlockNote +
+ Hi{name ? ` ${name}` : ""}, + + Thanks for signing up for BlockNote! To complete your + registration, please verify your email address by clicking the + button below: + + + + If you didn't create a BlockNote account, you can safely + ignore this email. + + + To keep your account secure, please don't forward this email + to anyone. + +
+
+ + + ); +}; + +VerifyEmail.PreviewProps = { + name: "", + url: "https://blocknotejs.org", +} as VerifyEmailProps; + +export default VerifyEmail; + +const main = { + backgroundColor: "#f6f9fc", + padding: "10px 0", +}; + +const container = { + backgroundColor: "#ffffff", + border: "1px solid #f0f0f0", + padding: "45px", +}; + +const text = { + fontSize: "16px", + fontFamily: + "'Open Sans', 'HelveticaNeue-Light', 'Helvetica Neue Light', 'Helvetica Neue', Helvetica, Arial, 'Lucida Grande', sans-serif", + fontWeight: "300", + color: "#404040", + lineHeight: "26px", +}; + +const button = { + backgroundColor: "#007ee6", + borderRadius: "4px", + color: "#fff", + fontFamily: "'Open Sans', 'Helvetica Neue', Arial", + fontSize: "15px", + textDecoration: "none", + textAlign: "center" as const, + display: "block", + width: "210px", + padding: "14px 7px", +}; diff --git a/docs/package.json b/docs/package.json index 27fa0123ea..916cfa2447 100644 --- a/docs/package.json +++ b/docs/package.json @@ -4,6 +4,8 @@ "private": true, "scripts": { "dev": "next dev", + "dev:email": "email dev", + "build:email": "email export --outDir ./", "build:site": "next build", "start": "next start", "lint": "next lint" @@ -20,9 +22,10 @@ "@heroicons/react": "^2.1.4", "@mantine/core": "^7.10.1", "@next/bundle-analyzer": "^14.1.0", - "@polar-sh/better-auth": "0.1.0", - "@polar-sh/nextjs": "0.3.23", - "@polar-sh/sdk": "0.32.10", + "@polar-sh/better-auth": "^0.1", + "@polar-sh/nextjs": "^0.3.23", + "@polar-sh/sdk": "^0.32.11", + "@react-email/render": "1.0.6", "@sentry/nextjs": "9.4.0", "@types/better-sqlite3": "7.6.13", "@types/nodemailer": "6.4.17", @@ -49,6 +52,7 @@ "zod": "^3.23.8" }, "devDependencies": { + "@react-email/components": "^0.0.36", "@types/node": "^20", "@types/react": "^18.0.25", "@types/react-dom": "^18.0.9", @@ -56,6 +60,7 @@ "eslint": "^8", "eslint-config-next": "14.1.0", "postcss": "^8", + "react-email": "^4.0.7", "tailwindcss": "^3.3.0", "typescript": "^5" } diff --git a/docs/theme.config.tsx b/docs/theme.config.tsx index c04826a1ba..0fd892d77f 100644 --- a/docs/theme.config.tsx +++ b/docs/theme.config.tsx @@ -222,11 +222,11 @@ const config: DocsThemeConfig = { Discord - {/* - + + Sign in - */} + ); diff --git a/docs/util/auth-client.ts b/docs/util/auth-client.ts index 314e890ab5..a76177f15e 100644 --- a/docs/util/auth-client.ts +++ b/docs/util/auth-client.ts @@ -1,7 +1,9 @@ -import { createAuthClient } from "better-auth/react" +import { createAuthClient } from "better-auth/react"; + +import { magicLinkClient } from "better-auth/client/plugins"; + export const authClient = createAuthClient({ - /** The base URL of the server (optional if you're using the same domain) */ - baseURL: "http://localhost:3000" -}) + plugins: [magicLinkClient()], +}); -export const { useSession, signIn, signOut, signUp } = authClient \ No newline at end of file +export const { useSession, signIn, signOut, signUp } = authClient; diff --git a/docs/util/send-mail.tsx b/docs/util/send-mail.tsx new file mode 100644 index 0000000000..702f9378b1 --- /dev/null +++ b/docs/util/send-mail.tsx @@ -0,0 +1,86 @@ +import nodemailer from "nodemailer"; +import { render } from "@react-email/render"; +import MagicLinkEmail from "@/emails/magic-link"; +import VerifyEmail from "@/emails/verify-email"; +import ResetPassword from "@/emails/reset-password"; + +const transporter = nodemailer.createTransport({ + host: String(process.env.SMTP_HOST), + port: Number(process.env.SMTP_PORT), + secure: process.env.SMTP_SECURE !== "false", // true for port 465, false for other ports + auth: { + user: String(process.env.SMTP_USER), + pass: String(process.env.SMTP_PASS), + }, +}); + +type TEMPLATES = { + verifyEmail: { + url: string; + name?: string; + }; + resetPassword: { + url: string; + name?: string; + }; + magicLink: { + url: string; + name?: string; + }; +}; + +const TEMPLATE_TEXTS = { + verifyEmail: (props: TEMPLATES["verifyEmail"]) => + render(, { + pretty: true, + plainText: true, + }), + resetPassword: (props: TEMPLATES["resetPassword"]) => + render(, { + pretty: true, + plainText: true, + }), + magicLink: (props: TEMPLATES["magicLink"]) => + render(, { + pretty: true, + plainText: true, + }), +}; +const TEMPLATE_HTMLS = { + verifyEmail: (props: TEMPLATES["verifyEmail"]) => + render(, { + pretty: true, + }), + resetPassword: (props: TEMPLATES["resetPassword"]) => + render(, { + pretty: true, + }), + magicLink: (props: TEMPLATES["magicLink"]): Promise => + render(, { + pretty: true, + }), +}; + +export async function sendEmail({ + to, + template, + props, +}: { + to: string; + template: T; + props: TEMPLATES[T]; +}) { + const info = await transporter.sendMail({ + from: '"BlockNote" ', + to, + subject: { + verifyEmail: "BlockNote - Verify your email address", + resetPassword: "BlockNote - Reset your password", + magicLink: "BlockNote - Sign in to your account", + }[template], + text: await TEMPLATE_TEXTS[template](props), + html: await TEMPLATE_HTMLS[template](props), + }); + + console.log("Email sent: ", info.messageId); +} diff --git a/package.json b/package.json index e7f83a9a7c..3618f79eb6 100644 --- a/package.json +++ b/package.json @@ -38,7 +38,7 @@ "dev:docs": "nx run docs:dev", "build": "nx run-many --target=build", "build:clean": "pnpm run clean && pnpm run gen && pnpm run clean && pnpm run build", - "build:site": "pnpm run gen && nx run docs:build:site", + "build:site": "pnpm run gen && nx run-many --target=build:site", "clean": "nx run-many --target=clean", "deploy": "nx release --skip-publish", "gen": "nx run @blocknote/dev-scripts:gen", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 81450f204e..b4f82ad6db 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -49,7 +49,7 @@ importers: version: 5.8.2 vitest: specifier: ^2.0.3 - version: 2.1.9(@types/node@22.13.13)(@vitest/ui@2.1.9)(jsdom@25.0.1(canvas@2.11.2(encoding@0.1.13)))(terser@5.39.0) + version: 2.1.9(@types/node@22.14.1)(@vitest/ui@2.1.9)(jsdom@25.0.1(canvas@2.11.2(encoding@0.1.13)))(terser@5.39.0) wait-on: specifier: 8.0.3 version: 8.0.3 @@ -90,14 +90,17 @@ importers: specifier: ^14.1.0 version: 14.2.26 '@polar-sh/better-auth': - specifier: 0.1.0 - version: 0.1.0(@polar-sh/sdk@0.32.10(zod@3.24.2))(better-auth@1.2.7) + specifier: ^0.1 + version: 0.1.0(@polar-sh/sdk@0.32.11(zod@3.24.2))(better-auth@1.2.7) '@polar-sh/nextjs': - specifier: 0.3.23 + specifier: ^0.3.23 version: 0.3.23(next@15.2.4(@babel/core@7.26.10)(@opentelemetry/api@1.9.0)(@playwright/test@1.51.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(zod@3.24.2) '@polar-sh/sdk': - specifier: 0.32.10 - version: 0.32.10(zod@3.24.2) + specifier: ^0.32.11 + version: 0.32.11(zod@3.24.2) + '@react-email/render': + specifier: 1.0.6 + version: 1.0.6(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@sentry/nextjs': specifier: 9.4.0 version: 9.4.0(@opentelemetry/context-async-hooks@1.30.1(@opentelemetry/api@1.9.0))(@opentelemetry/core@1.30.1(@opentelemetry/api@1.9.0))(@opentelemetry/instrumentation@0.57.2(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@1.30.1(@opentelemetry/api@1.9.0))(encoding@0.1.13)(next@15.2.4(@babel/core@7.26.10)(@opentelemetry/api@1.9.0)(@playwright/test@1.51.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1)(webpack@5.98.0) @@ -171,6 +174,9 @@ importers: specifier: ^3.23.8 version: 3.24.2 devDependencies: + '@react-email/components': + specifier: ^0.0.36 + version: 0.0.36(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@types/node': specifier: ^20 version: 20.17.28 @@ -192,6 +198,9 @@ importers: postcss: specifier: ^8 version: 8.5.3 + react-email: + specifier: ^4.0.7 + version: 4.0.7(@babel/core@7.26.10)(@opentelemetry/api@1.9.0)(@playwright/test@1.51.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) tailwindcss: specifier: ^3.3.0 version: 3.4.17 @@ -231,10 +240,10 @@ importers: version: 18.3.5(@types/react@18.3.20) '@vitejs/plugin-react': specifier: ^4.3.1 - version: 4.3.4(vite@5.4.15(@types/node@22.13.13)(terser@5.39.0)) + version: 4.3.4(vite@5.4.15(@types/node@22.14.1)(terser@5.39.0)) vite: specifier: ^5.3.4 - version: 5.4.15(@types/node@22.13.13)(terser@5.39.0) + version: 5.4.15(@types/node@22.14.1)(terser@5.39.0) examples/01-basic/02-block-objects: dependencies: @@ -268,10 +277,10 @@ importers: version: 18.3.5(@types/react@18.3.20) '@vitejs/plugin-react': specifier: ^4.3.1 - version: 4.3.4(vite@5.4.15(@types/node@22.13.13)(terser@5.39.0)) + version: 4.3.4(vite@5.4.15(@types/node@22.14.1)(terser@5.39.0)) vite: specifier: ^5.3.4 - version: 5.4.15(@types/node@22.13.13)(terser@5.39.0) + version: 5.4.15(@types/node@22.14.1)(terser@5.39.0) examples/01-basic/03-multi-column: dependencies: @@ -308,10 +317,10 @@ importers: version: 18.3.5(@types/react@18.3.20) '@vitejs/plugin-react': specifier: ^4.3.1 - version: 4.3.4(vite@5.4.15(@types/node@22.13.13)(terser@5.39.0)) + version: 4.3.4(vite@5.4.15(@types/node@22.14.1)(terser@5.39.0)) vite: specifier: ^5.3.4 - version: 5.4.15(@types/node@22.13.13)(terser@5.39.0) + version: 5.4.15(@types/node@22.14.1)(terser@5.39.0) examples/01-basic/04-default-blocks: dependencies: @@ -345,10 +354,10 @@ importers: version: 18.3.5(@types/react@18.3.20) '@vitejs/plugin-react': specifier: ^4.3.1 - version: 4.3.4(vite@5.4.15(@types/node@22.13.13)(terser@5.39.0)) + version: 4.3.4(vite@5.4.15(@types/node@22.14.1)(terser@5.39.0)) vite: specifier: ^5.3.4 - version: 5.4.15(@types/node@22.13.13)(terser@5.39.0) + version: 5.4.15(@types/node@22.14.1)(terser@5.39.0) examples/01-basic/05-removing-default-blocks: dependencies: @@ -382,10 +391,10 @@ importers: version: 18.3.5(@types/react@18.3.20) '@vitejs/plugin-react': specifier: ^4.3.1 - version: 4.3.4(vite@5.4.15(@types/node@22.13.13)(terser@5.39.0)) + version: 4.3.4(vite@5.4.15(@types/node@22.14.1)(terser@5.39.0)) vite: specifier: ^5.3.4 - version: 5.4.15(@types/node@22.13.13)(terser@5.39.0) + version: 5.4.15(@types/node@22.14.1)(terser@5.39.0) examples/01-basic/06-block-manipulation: dependencies: @@ -419,10 +428,10 @@ importers: version: 18.3.5(@types/react@18.3.20) '@vitejs/plugin-react': specifier: ^4.3.1 - version: 4.3.4(vite@5.4.15(@types/node@22.13.13)(terser@5.39.0)) + version: 4.3.4(vite@5.4.15(@types/node@22.14.1)(terser@5.39.0)) vite: specifier: ^5.3.4 - version: 5.4.15(@types/node@22.13.13)(terser@5.39.0) + version: 5.4.15(@types/node@22.14.1)(terser@5.39.0) examples/01-basic/07-selection-blocks: dependencies: @@ -456,10 +465,10 @@ importers: version: 18.3.5(@types/react@18.3.20) '@vitejs/plugin-react': specifier: ^4.3.1 - version: 4.3.4(vite@5.4.15(@types/node@22.13.13)(terser@5.39.0)) + version: 4.3.4(vite@5.4.15(@types/node@22.14.1)(terser@5.39.0)) vite: specifier: ^5.3.4 - version: 5.4.15(@types/node@22.13.13)(terser@5.39.0) + version: 5.4.15(@types/node@22.14.1)(terser@5.39.0) examples/01-basic/08-ariakit: dependencies: @@ -493,10 +502,10 @@ importers: version: 18.3.5(@types/react@18.3.20) '@vitejs/plugin-react': specifier: ^4.3.1 - version: 4.3.4(vite@5.4.15(@types/node@22.13.13)(terser@5.39.0)) + version: 4.3.4(vite@5.4.15(@types/node@22.14.1)(terser@5.39.0)) vite: specifier: ^5.3.4 - version: 5.4.15(@types/node@22.13.13)(terser@5.39.0) + version: 5.4.15(@types/node@22.14.1)(terser@5.39.0) examples/01-basic/09-shadcn: dependencies: @@ -530,10 +539,10 @@ importers: version: 18.3.5(@types/react@18.3.20) '@vitejs/plugin-react': specifier: ^4.3.1 - version: 4.3.4(vite@5.4.15(@types/node@22.13.13)(terser@5.39.0)) + version: 4.3.4(vite@5.4.15(@types/node@22.14.1)(terser@5.39.0)) vite: specifier: ^5.3.4 - version: 5.4.15(@types/node@22.13.13)(terser@5.39.0) + version: 5.4.15(@types/node@22.14.1)(terser@5.39.0) examples/01-basic/10-localization: dependencies: @@ -567,10 +576,10 @@ importers: version: 18.3.5(@types/react@18.3.20) '@vitejs/plugin-react': specifier: ^4.3.1 - version: 4.3.4(vite@5.4.15(@types/node@22.13.13)(terser@5.39.0)) + version: 4.3.4(vite@5.4.15(@types/node@22.14.1)(terser@5.39.0)) vite: specifier: ^5.3.4 - version: 5.4.15(@types/node@22.13.13)(terser@5.39.0) + version: 5.4.15(@types/node@22.14.1)(terser@5.39.0) examples/01-basic/11-custom-placeholder: dependencies: @@ -604,10 +613,10 @@ importers: version: 18.3.5(@types/react@18.3.20) '@vitejs/plugin-react': specifier: ^4.3.1 - version: 4.3.4(vite@5.4.15(@types/node@22.13.13)(terser@5.39.0)) + version: 4.3.4(vite@5.4.15(@types/node@22.14.1)(terser@5.39.0)) vite: specifier: ^5.3.4 - version: 5.4.15(@types/node@22.13.13)(terser@5.39.0) + version: 5.4.15(@types/node@22.14.1)(terser@5.39.0) examples/01-basic/12-multi-editor: dependencies: @@ -641,10 +650,10 @@ importers: version: 18.3.5(@types/react@18.3.20) '@vitejs/plugin-react': specifier: ^4.3.1 - version: 4.3.4(vite@5.4.15(@types/node@22.13.13)(terser@5.39.0)) + version: 4.3.4(vite@5.4.15(@types/node@22.14.1)(terser@5.39.0)) vite: specifier: ^5.3.4 - version: 5.4.15(@types/node@22.13.13)(terser@5.39.0) + version: 5.4.15(@types/node@22.14.1)(terser@5.39.0) examples/01-basic/13-custom-paste-handler: dependencies: @@ -678,10 +687,10 @@ importers: version: 18.3.5(@types/react@18.3.20) '@vitejs/plugin-react': specifier: ^4.3.1 - version: 4.3.4(vite@5.4.15(@types/node@22.13.13)(terser@5.39.0)) + version: 4.3.4(vite@5.4.15(@types/node@22.14.1)(terser@5.39.0)) vite: specifier: ^5.3.4 - version: 5.4.15(@types/node@22.13.13)(terser@5.39.0) + version: 5.4.15(@types/node@22.14.1)(terser@5.39.0) examples/01-basic/testing: dependencies: @@ -715,10 +724,10 @@ importers: version: 18.3.5(@types/react@18.3.20) '@vitejs/plugin-react': specifier: ^4.3.1 - version: 4.3.4(vite@5.4.15(@types/node@22.13.13)(terser@5.39.0)) + version: 4.3.4(vite@5.4.15(@types/node@22.14.1)(terser@5.39.0)) vite: specifier: ^5.3.4 - version: 5.4.15(@types/node@22.13.13)(terser@5.39.0) + version: 5.4.15(@types/node@22.14.1)(terser@5.39.0) examples/02-backend/01-file-uploading: dependencies: @@ -752,10 +761,10 @@ importers: version: 18.3.5(@types/react@18.3.20) '@vitejs/plugin-react': specifier: ^4.3.1 - version: 4.3.4(vite@5.4.15(@types/node@22.13.13)(terser@5.39.0)) + version: 4.3.4(vite@5.4.15(@types/node@22.14.1)(terser@5.39.0)) vite: specifier: ^5.3.4 - version: 5.4.15(@types/node@22.13.13)(terser@5.39.0) + version: 5.4.15(@types/node@22.14.1)(terser@5.39.0) examples/02-backend/02-saving-loading: dependencies: @@ -789,10 +798,10 @@ importers: version: 18.3.5(@types/react@18.3.20) '@vitejs/plugin-react': specifier: ^4.3.1 - version: 4.3.4(vite@5.4.15(@types/node@22.13.13)(terser@5.39.0)) + version: 4.3.4(vite@5.4.15(@types/node@22.14.1)(terser@5.39.0)) vite: specifier: ^5.3.4 - version: 5.4.15(@types/node@22.13.13)(terser@5.39.0) + version: 5.4.15(@types/node@22.14.1)(terser@5.39.0) examples/02-backend/03-s3: dependencies: @@ -832,10 +841,10 @@ importers: version: 18.3.5(@types/react@18.3.20) '@vitejs/plugin-react': specifier: ^4.3.1 - version: 4.3.4(vite@5.4.15(@types/node@22.13.13)(terser@5.39.0)) + version: 4.3.4(vite@5.4.15(@types/node@22.14.1)(terser@5.39.0)) vite: specifier: ^5.3.4 - version: 5.4.15(@types/node@22.13.13)(terser@5.39.0) + version: 5.4.15(@types/node@22.14.1)(terser@5.39.0) examples/02-backend/04-rendering-static-documents: dependencies: @@ -872,10 +881,10 @@ importers: version: 18.3.5(@types/react@18.3.20) '@vitejs/plugin-react': specifier: ^4.3.1 - version: 4.3.4(vite@5.4.15(@types/node@22.13.13)(terser@5.39.0)) + version: 4.3.4(vite@5.4.15(@types/node@22.14.1)(terser@5.39.0)) vite: specifier: ^5.3.4 - version: 5.4.15(@types/node@22.13.13)(terser@5.39.0) + version: 5.4.15(@types/node@22.14.1)(terser@5.39.0) examples/03-ui-components/01-ui-elements-remove: dependencies: @@ -909,10 +918,10 @@ importers: version: 18.3.5(@types/react@18.3.20) '@vitejs/plugin-react': specifier: ^4.3.1 - version: 4.3.4(vite@5.4.15(@types/node@22.13.13)(terser@5.39.0)) + version: 4.3.4(vite@5.4.15(@types/node@22.14.1)(terser@5.39.0)) vite: specifier: ^5.3.4 - version: 5.4.15(@types/node@22.13.13)(terser@5.39.0) + version: 5.4.15(@types/node@22.14.1)(terser@5.39.0) examples/03-ui-components/02-formatting-toolbar-buttons: dependencies: @@ -946,10 +955,10 @@ importers: version: 18.3.5(@types/react@18.3.20) '@vitejs/plugin-react': specifier: ^4.3.1 - version: 4.3.4(vite@5.4.15(@types/node@22.13.13)(terser@5.39.0)) + version: 4.3.4(vite@5.4.15(@types/node@22.14.1)(terser@5.39.0)) vite: specifier: ^5.3.4 - version: 5.4.15(@types/node@22.13.13)(terser@5.39.0) + version: 5.4.15(@types/node@22.14.1)(terser@5.39.0) examples/03-ui-components/03-formatting-toolbar-block-type-items: dependencies: @@ -989,10 +998,10 @@ importers: version: 18.3.5(@types/react@18.3.20) '@vitejs/plugin-react': specifier: ^4.3.1 - version: 4.3.4(vite@5.4.15(@types/node@22.13.13)(terser@5.39.0)) + version: 4.3.4(vite@5.4.15(@types/node@22.14.1)(terser@5.39.0)) vite: specifier: ^5.3.4 - version: 5.4.15(@types/node@22.13.13)(terser@5.39.0) + version: 5.4.15(@types/node@22.14.1)(terser@5.39.0) examples/03-ui-components/04-side-menu-buttons: dependencies: @@ -1029,10 +1038,10 @@ importers: version: 18.3.5(@types/react@18.3.20) '@vitejs/plugin-react': specifier: ^4.3.1 - version: 4.3.4(vite@5.4.15(@types/node@22.13.13)(terser@5.39.0)) + version: 4.3.4(vite@5.4.15(@types/node@22.14.1)(terser@5.39.0)) vite: specifier: ^5.3.4 - version: 5.4.15(@types/node@22.13.13)(terser@5.39.0) + version: 5.4.15(@types/node@22.14.1)(terser@5.39.0) examples/03-ui-components/05-side-menu-drag-handle-items: dependencies: @@ -1069,10 +1078,10 @@ importers: version: 18.3.5(@types/react@18.3.20) '@vitejs/plugin-react': specifier: ^4.3.1 - version: 4.3.4(vite@5.4.15(@types/node@22.13.13)(terser@5.39.0)) + version: 4.3.4(vite@5.4.15(@types/node@22.14.1)(terser@5.39.0)) vite: specifier: ^5.3.4 - version: 5.4.15(@types/node@22.13.13)(terser@5.39.0) + version: 5.4.15(@types/node@22.14.1)(terser@5.39.0) examples/03-ui-components/06-suggestion-menus-slash-menu-items: dependencies: @@ -1109,10 +1118,10 @@ importers: version: 18.3.5(@types/react@18.3.20) '@vitejs/plugin-react': specifier: ^4.3.1 - version: 4.3.4(vite@5.4.15(@types/node@22.13.13)(terser@5.39.0)) + version: 4.3.4(vite@5.4.15(@types/node@22.14.1)(terser@5.39.0)) vite: specifier: ^5.3.4 - version: 5.4.15(@types/node@22.13.13)(terser@5.39.0) + version: 5.4.15(@types/node@22.14.1)(terser@5.39.0) examples/03-ui-components/07-suggestion-menus-slash-menu-component: dependencies: @@ -1146,10 +1155,10 @@ importers: version: 18.3.5(@types/react@18.3.20) '@vitejs/plugin-react': specifier: ^4.3.1 - version: 4.3.4(vite@5.4.15(@types/node@22.13.13)(terser@5.39.0)) + version: 4.3.4(vite@5.4.15(@types/node@22.14.1)(terser@5.39.0)) vite: specifier: ^5.3.4 - version: 5.4.15(@types/node@22.13.13)(terser@5.39.0) + version: 5.4.15(@types/node@22.14.1)(terser@5.39.0) examples/03-ui-components/08-suggestion-menus-emoji-picker-columns: dependencies: @@ -1183,10 +1192,10 @@ importers: version: 18.3.5(@types/react@18.3.20) '@vitejs/plugin-react': specifier: ^4.3.1 - version: 4.3.4(vite@5.4.15(@types/node@22.13.13)(terser@5.39.0)) + version: 4.3.4(vite@5.4.15(@types/node@22.14.1)(terser@5.39.0)) vite: specifier: ^5.3.4 - version: 5.4.15(@types/node@22.13.13)(terser@5.39.0) + version: 5.4.15(@types/node@22.14.1)(terser@5.39.0) examples/03-ui-components/09-suggestion-menus-emoji-picker-component: dependencies: @@ -1220,10 +1229,10 @@ importers: version: 18.3.5(@types/react@18.3.20) '@vitejs/plugin-react': specifier: ^4.3.1 - version: 4.3.4(vite@5.4.15(@types/node@22.13.13)(terser@5.39.0)) + version: 4.3.4(vite@5.4.15(@types/node@22.14.1)(terser@5.39.0)) vite: specifier: ^5.3.4 - version: 5.4.15(@types/node@22.13.13)(terser@5.39.0) + version: 5.4.15(@types/node@22.14.1)(terser@5.39.0) examples/03-ui-components/10-suggestion-menus-grid-mentions: dependencies: @@ -1257,10 +1266,10 @@ importers: version: 18.3.5(@types/react@18.3.20) '@vitejs/plugin-react': specifier: ^4.3.1 - version: 4.3.4(vite@5.4.15(@types/node@22.13.13)(terser@5.39.0)) + version: 4.3.4(vite@5.4.15(@types/node@22.14.1)(terser@5.39.0)) vite: specifier: ^5.3.4 - version: 5.4.15(@types/node@22.13.13)(terser@5.39.0) + version: 5.4.15(@types/node@22.14.1)(terser@5.39.0) examples/03-ui-components/11-uppy-file-panel: dependencies: @@ -1330,10 +1339,10 @@ importers: version: 18.3.5(@types/react@18.3.20) '@vitejs/plugin-react': specifier: ^4.3.1 - version: 4.3.4(vite@5.4.15(@types/node@22.13.13)(terser@5.39.0)) + version: 4.3.4(vite@5.4.15(@types/node@22.14.1)(terser@5.39.0)) vite: specifier: ^5.3.4 - version: 5.4.15(@types/node@22.13.13)(terser@5.39.0) + version: 5.4.15(@types/node@22.14.1)(terser@5.39.0) examples/03-ui-components/12-static-formatting-toolbar: dependencies: @@ -1367,10 +1376,10 @@ importers: version: 18.3.5(@types/react@18.3.20) '@vitejs/plugin-react': specifier: ^4.3.1 - version: 4.3.4(vite@5.4.15(@types/node@22.13.13)(terser@5.39.0)) + version: 4.3.4(vite@5.4.15(@types/node@22.14.1)(terser@5.39.0)) vite: specifier: ^5.3.4 - version: 5.4.15(@types/node@22.13.13)(terser@5.39.0) + version: 5.4.15(@types/node@22.14.1)(terser@5.39.0) examples/03-ui-components/13-custom-ui: dependencies: @@ -1416,10 +1425,10 @@ importers: version: 18.3.5(@types/react@18.3.20) '@vitejs/plugin-react': specifier: ^4.3.1 - version: 4.3.4(vite@5.4.15(@types/node@22.13.13)(terser@5.39.0)) + version: 4.3.4(vite@5.4.15(@types/node@22.14.1)(terser@5.39.0)) vite: specifier: ^5.3.4 - version: 5.4.15(@types/node@22.13.13)(terser@5.39.0) + version: 5.4.15(@types/node@22.14.1)(terser@5.39.0) examples/03-ui-components/14-experimental-mobile-formatting-toolbar: dependencies: @@ -1453,10 +1462,10 @@ importers: version: 18.3.5(@types/react@18.3.20) '@vitejs/plugin-react': specifier: ^4.3.1 - version: 4.3.4(vite@5.4.15(@types/node@22.13.13)(terser@5.39.0)) + version: 4.3.4(vite@5.4.15(@types/node@22.14.1)(terser@5.39.0)) vite: specifier: ^5.3.4 - version: 5.4.15(@types/node@22.13.13)(terser@5.39.0) + version: 5.4.15(@types/node@22.14.1)(terser@5.39.0) examples/03-ui-components/15-advanced-tables: dependencies: @@ -1490,10 +1499,10 @@ importers: version: 18.3.5(@types/react@18.3.20) '@vitejs/plugin-react': specifier: ^4.3.1 - version: 4.3.4(vite@5.4.15(@types/node@22.13.13)(terser@5.39.0)) + version: 4.3.4(vite@5.4.15(@types/node@22.14.1)(terser@5.39.0)) vite: specifier: ^5.3.4 - version: 5.4.15(@types/node@22.13.13)(terser@5.39.0) + version: 5.4.15(@types/node@22.14.1)(terser@5.39.0) examples/03-ui-components/link-toolbar-buttons: dependencies: @@ -1527,10 +1536,10 @@ importers: version: 18.3.5(@types/react@18.3.20) '@vitejs/plugin-react': specifier: ^4.3.1 - version: 4.3.4(vite@5.4.15(@types/node@22.13.13)(terser@5.39.0)) + version: 4.3.4(vite@5.4.15(@types/node@22.14.1)(terser@5.39.0)) vite: specifier: ^5.3.4 - version: 5.4.15(@types/node@22.13.13)(terser@5.39.0) + version: 5.4.15(@types/node@22.14.1)(terser@5.39.0) examples/04-theming/01-theming-dom-attributes: dependencies: @@ -1564,10 +1573,10 @@ importers: version: 18.3.5(@types/react@18.3.20) '@vitejs/plugin-react': specifier: ^4.3.1 - version: 4.3.4(vite@5.4.15(@types/node@22.13.13)(terser@5.39.0)) + version: 4.3.4(vite@5.4.15(@types/node@22.14.1)(terser@5.39.0)) vite: specifier: ^5.3.4 - version: 5.4.15(@types/node@22.13.13)(terser@5.39.0) + version: 5.4.15(@types/node@22.14.1)(terser@5.39.0) examples/04-theming/02-changing-font: dependencies: @@ -1601,10 +1610,10 @@ importers: version: 18.3.5(@types/react@18.3.20) '@vitejs/plugin-react': specifier: ^4.3.1 - version: 4.3.4(vite@5.4.15(@types/node@22.13.13)(terser@5.39.0)) + version: 4.3.4(vite@5.4.15(@types/node@22.14.1)(terser@5.39.0)) vite: specifier: ^5.3.4 - version: 5.4.15(@types/node@22.13.13)(terser@5.39.0) + version: 5.4.15(@types/node@22.14.1)(terser@5.39.0) examples/04-theming/03-theming-css: dependencies: @@ -1638,10 +1647,10 @@ importers: version: 18.3.5(@types/react@18.3.20) '@vitejs/plugin-react': specifier: ^4.3.1 - version: 4.3.4(vite@5.4.15(@types/node@22.13.13)(terser@5.39.0)) + version: 4.3.4(vite@5.4.15(@types/node@22.14.1)(terser@5.39.0)) vite: specifier: ^5.3.4 - version: 5.4.15(@types/node@22.13.13)(terser@5.39.0) + version: 5.4.15(@types/node@22.14.1)(terser@5.39.0) examples/04-theming/04-theming-css-variables: dependencies: @@ -1675,10 +1684,10 @@ importers: version: 18.3.5(@types/react@18.3.20) '@vitejs/plugin-react': specifier: ^4.3.1 - version: 4.3.4(vite@5.4.15(@types/node@22.13.13)(terser@5.39.0)) + version: 4.3.4(vite@5.4.15(@types/node@22.14.1)(terser@5.39.0)) vite: specifier: ^5.3.4 - version: 5.4.15(@types/node@22.13.13)(terser@5.39.0) + version: 5.4.15(@types/node@22.14.1)(terser@5.39.0) examples/04-theming/05-theming-css-variables-code: dependencies: @@ -1712,10 +1721,10 @@ importers: version: 18.3.5(@types/react@18.3.20) '@vitejs/plugin-react': specifier: ^4.3.1 - version: 4.3.4(vite@5.4.15(@types/node@22.13.13)(terser@5.39.0)) + version: 4.3.4(vite@5.4.15(@types/node@22.14.1)(terser@5.39.0)) vite: specifier: ^5.3.4 - version: 5.4.15(@types/node@22.13.13)(terser@5.39.0) + version: 5.4.15(@types/node@22.14.1)(terser@5.39.0) examples/04-theming/06-code-block: dependencies: @@ -1752,10 +1761,10 @@ importers: version: 18.3.5(@types/react@18.3.20) '@vitejs/plugin-react': specifier: ^4.3.1 - version: 4.3.4(vite@5.4.15(@types/node@22.13.13)(terser@5.39.0)) + version: 4.3.4(vite@5.4.15(@types/node@22.14.1)(terser@5.39.0)) vite: specifier: ^5.3.4 - version: 5.4.15(@types/node@22.13.13)(terser@5.39.0) + version: 5.4.15(@types/node@22.14.1)(terser@5.39.0) examples/04-theming/07-custom-code-block: dependencies: @@ -1807,10 +1816,10 @@ importers: version: 18.3.5(@types/react@18.3.20) '@vitejs/plugin-react': specifier: ^4.3.1 - version: 4.3.4(vite@5.4.15(@types/node@22.13.13)(terser@5.39.0)) + version: 4.3.4(vite@5.4.15(@types/node@22.14.1)(terser@5.39.0)) vite: specifier: ^5.3.4 - version: 5.4.15(@types/node@22.13.13)(terser@5.39.0) + version: 5.4.15(@types/node@22.14.1)(terser@5.39.0) examples/05-interoperability/01-converting-blocks-to-html: dependencies: @@ -1844,10 +1853,10 @@ importers: version: 18.3.5(@types/react@18.3.20) '@vitejs/plugin-react': specifier: ^4.3.1 - version: 4.3.4(vite@5.4.15(@types/node@22.13.13)(terser@5.39.0)) + version: 4.3.4(vite@5.4.15(@types/node@22.14.1)(terser@5.39.0)) vite: specifier: ^5.3.4 - version: 5.4.15(@types/node@22.13.13)(terser@5.39.0) + version: 5.4.15(@types/node@22.14.1)(terser@5.39.0) examples/05-interoperability/02-converting-blocks-from-html: dependencies: @@ -1881,10 +1890,10 @@ importers: version: 18.3.5(@types/react@18.3.20) '@vitejs/plugin-react': specifier: ^4.3.1 - version: 4.3.4(vite@5.4.15(@types/node@22.13.13)(terser@5.39.0)) + version: 4.3.4(vite@5.4.15(@types/node@22.14.1)(terser@5.39.0)) vite: specifier: ^5.3.4 - version: 5.4.15(@types/node@22.13.13)(terser@5.39.0) + version: 5.4.15(@types/node@22.14.1)(terser@5.39.0) examples/05-interoperability/03-converting-blocks-to-md: dependencies: @@ -1918,10 +1927,10 @@ importers: version: 18.3.5(@types/react@18.3.20) '@vitejs/plugin-react': specifier: ^4.3.1 - version: 4.3.4(vite@5.4.15(@types/node@22.13.13)(terser@5.39.0)) + version: 4.3.4(vite@5.4.15(@types/node@22.14.1)(terser@5.39.0)) vite: specifier: ^5.3.4 - version: 5.4.15(@types/node@22.13.13)(terser@5.39.0) + version: 5.4.15(@types/node@22.14.1)(terser@5.39.0) examples/05-interoperability/04-converting-blocks-from-md: dependencies: @@ -1955,10 +1964,10 @@ importers: version: 18.3.5(@types/react@18.3.20) '@vitejs/plugin-react': specifier: ^4.3.1 - version: 4.3.4(vite@5.4.15(@types/node@22.13.13)(terser@5.39.0)) + version: 4.3.4(vite@5.4.15(@types/node@22.14.1)(terser@5.39.0)) vite: specifier: ^5.3.4 - version: 5.4.15(@types/node@22.13.13)(terser@5.39.0) + version: 5.4.15(@types/node@22.14.1)(terser@5.39.0) examples/05-interoperability/05-converting-blocks-to-pdf: dependencies: @@ -1998,10 +2007,10 @@ importers: version: 18.3.5(@types/react@18.3.20) '@vitejs/plugin-react': specifier: ^4.3.1 - version: 4.3.4(vite@5.4.15(@types/node@22.13.13)(terser@5.39.0)) + version: 4.3.4(vite@5.4.15(@types/node@22.14.1)(terser@5.39.0)) vite: specifier: ^5.3.4 - version: 5.4.15(@types/node@22.13.13)(terser@5.39.0) + version: 5.4.15(@types/node@22.14.1)(terser@5.39.0) examples/05-interoperability/06-converting-blocks-to-docx: dependencies: @@ -2041,10 +2050,10 @@ importers: version: 18.3.5(@types/react@18.3.20) '@vitejs/plugin-react': specifier: ^4.3.1 - version: 4.3.4(vite@5.4.15(@types/node@22.13.13)(terser@5.39.0)) + version: 4.3.4(vite@5.4.15(@types/node@22.14.1)(terser@5.39.0)) vite: specifier: ^5.3.4 - version: 5.4.15(@types/node@22.13.13)(terser@5.39.0) + version: 5.4.15(@types/node@22.14.1)(terser@5.39.0) examples/05-interoperability/07-converting-blocks-to-odt: dependencies: @@ -2081,10 +2090,10 @@ importers: version: 18.3.5(@types/react@18.3.20) '@vitejs/plugin-react': specifier: ^4.3.1 - version: 4.3.4(vite@5.4.15(@types/node@22.13.13)(terser@5.39.0)) + version: 4.3.4(vite@5.4.15(@types/node@22.14.1)(terser@5.39.0)) vite: specifier: ^5.3.4 - version: 5.4.15(@types/node@22.13.13)(terser@5.39.0) + version: 5.4.15(@types/node@22.14.1)(terser@5.39.0) examples/06-custom-schema/01-alert-block: dependencies: @@ -2124,10 +2133,10 @@ importers: version: 18.3.5(@types/react@18.3.20) '@vitejs/plugin-react': specifier: ^4.3.1 - version: 4.3.4(vite@5.4.15(@types/node@22.13.13)(terser@5.39.0)) + version: 4.3.4(vite@5.4.15(@types/node@22.14.1)(terser@5.39.0)) vite: specifier: ^5.3.4 - version: 5.4.15(@types/node@22.13.13)(terser@5.39.0) + version: 5.4.15(@types/node@22.14.1)(terser@5.39.0) examples/06-custom-schema/02-suggestion-menus-mentions: dependencies: @@ -2161,10 +2170,10 @@ importers: version: 18.3.5(@types/react@18.3.20) '@vitejs/plugin-react': specifier: ^4.3.1 - version: 4.3.4(vite@5.4.15(@types/node@22.13.13)(terser@5.39.0)) + version: 4.3.4(vite@5.4.15(@types/node@22.14.1)(terser@5.39.0)) vite: specifier: ^5.3.4 - version: 5.4.15(@types/node@22.13.13)(terser@5.39.0) + version: 5.4.15(@types/node@22.14.1)(terser@5.39.0) examples/06-custom-schema/03-font-style: dependencies: @@ -2201,10 +2210,10 @@ importers: version: 18.3.5(@types/react@18.3.20) '@vitejs/plugin-react': specifier: ^4.3.1 - version: 4.3.4(vite@5.4.15(@types/node@22.13.13)(terser@5.39.0)) + version: 4.3.4(vite@5.4.15(@types/node@22.14.1)(terser@5.39.0)) vite: specifier: ^5.3.4 - version: 5.4.15(@types/node@22.13.13)(terser@5.39.0) + version: 5.4.15(@types/node@22.14.1)(terser@5.39.0) examples/06-custom-schema/04-pdf-file-block: dependencies: @@ -2244,10 +2253,10 @@ importers: version: 18.3.5(@types/react@18.3.20) '@vitejs/plugin-react': specifier: ^4.3.1 - version: 4.3.4(vite@5.4.15(@types/node@22.13.13)(terser@5.39.0)) + version: 4.3.4(vite@5.4.15(@types/node@22.14.1)(terser@5.39.0)) vite: specifier: ^5.3.4 - version: 5.4.15(@types/node@22.13.13)(terser@5.39.0) + version: 5.4.15(@types/node@22.14.1)(terser@5.39.0) examples/06-custom-schema/05-alert-block-full-ux: dependencies: @@ -2287,10 +2296,10 @@ importers: version: 18.3.5(@types/react@18.3.20) '@vitejs/plugin-react': specifier: ^4.3.1 - version: 4.3.4(vite@5.4.15(@types/node@22.13.13)(terser@5.39.0)) + version: 4.3.4(vite@5.4.15(@types/node@22.14.1)(terser@5.39.0)) vite: specifier: ^5.3.4 - version: 5.4.15(@types/node@22.13.13)(terser@5.39.0) + version: 5.4.15(@types/node@22.14.1)(terser@5.39.0) examples/06-custom-schema/react-custom-blocks: dependencies: @@ -2324,10 +2333,10 @@ importers: version: 18.3.5(@types/react@18.3.20) '@vitejs/plugin-react': specifier: ^4.3.1 - version: 4.3.4(vite@5.4.15(@types/node@22.13.13)(terser@5.39.0)) + version: 4.3.4(vite@5.4.15(@types/node@22.14.1)(terser@5.39.0)) vite: specifier: ^5.3.4 - version: 5.4.15(@types/node@22.13.13)(terser@5.39.0) + version: 5.4.15(@types/node@22.14.1)(terser@5.39.0) examples/06-custom-schema/react-custom-inline-content: dependencies: @@ -2361,10 +2370,10 @@ importers: version: 18.3.5(@types/react@18.3.20) '@vitejs/plugin-react': specifier: ^4.3.1 - version: 4.3.4(vite@5.4.15(@types/node@22.13.13)(terser@5.39.0)) + version: 4.3.4(vite@5.4.15(@types/node@22.14.1)(terser@5.39.0)) vite: specifier: ^5.3.4 - version: 5.4.15(@types/node@22.13.13)(terser@5.39.0) + version: 5.4.15(@types/node@22.14.1)(terser@5.39.0) examples/06-custom-schema/react-custom-styles: dependencies: @@ -2398,10 +2407,10 @@ importers: version: 18.3.5(@types/react@18.3.20) '@vitejs/plugin-react': specifier: ^4.3.1 - version: 4.3.4(vite@5.4.15(@types/node@22.13.13)(terser@5.39.0)) + version: 4.3.4(vite@5.4.15(@types/node@22.14.1)(terser@5.39.0)) vite: specifier: ^5.3.4 - version: 5.4.15(@types/node@22.13.13)(terser@5.39.0) + version: 5.4.15(@types/node@22.14.1)(terser@5.39.0) examples/07-collaboration/01-partykit: dependencies: @@ -2441,10 +2450,10 @@ importers: version: 18.3.5(@types/react@18.3.20) '@vitejs/plugin-react': specifier: ^4.3.1 - version: 4.3.4(vite@5.4.15(@types/node@22.13.13)(terser@5.39.0)) + version: 4.3.4(vite@5.4.15(@types/node@22.14.1)(terser@5.39.0)) vite: specifier: ^5.3.4 - version: 5.4.15(@types/node@22.13.13)(terser@5.39.0) + version: 5.4.15(@types/node@22.14.1)(terser@5.39.0) examples/07-collaboration/02-liveblocks: dependencies: @@ -2496,10 +2505,10 @@ importers: version: 18.3.5(@types/react@18.3.20) '@vitejs/plugin-react': specifier: ^4.3.1 - version: 4.3.4(vite@5.4.15(@types/node@22.13.13)(terser@5.39.0)) + version: 4.3.4(vite@5.4.15(@types/node@22.14.1)(terser@5.39.0)) vite: specifier: ^5.3.4 - version: 5.4.15(@types/node@22.13.13)(terser@5.39.0) + version: 5.4.15(@types/node@22.14.1)(terser@5.39.0) examples/07-collaboration/03-y-sweet: dependencies: @@ -2536,10 +2545,10 @@ importers: version: 18.3.5(@types/react@18.3.20) '@vitejs/plugin-react': specifier: ^4.3.1 - version: 4.3.4(vite@5.4.15(@types/node@22.13.13)(terser@5.39.0)) + version: 4.3.4(vite@5.4.15(@types/node@22.14.1)(terser@5.39.0)) vite: specifier: ^5.3.4 - version: 5.4.15(@types/node@22.13.13)(terser@5.39.0) + version: 5.4.15(@types/node@22.14.1)(terser@5.39.0) examples/07-collaboration/04-comments: dependencies: @@ -2579,10 +2588,10 @@ importers: version: 18.3.5(@types/react@18.3.20) '@vitejs/plugin-react': specifier: ^4.3.1 - version: 4.3.4(vite@5.4.15(@types/node@22.13.13)(terser@5.39.0)) + version: 4.3.4(vite@5.4.15(@types/node@22.14.1)(terser@5.39.0)) vite: specifier: ^5.3.4 - version: 5.4.15(@types/node@22.13.13)(terser@5.39.0) + version: 5.4.15(@types/node@22.14.1)(terser@5.39.0) examples/07-collaboration/05-comments-with-sidebar: dependencies: @@ -2622,10 +2631,10 @@ importers: version: 18.3.5(@types/react@18.3.20) '@vitejs/plugin-react': specifier: ^4.3.1 - version: 4.3.4(vite@5.4.15(@types/node@22.13.13)(terser@5.39.0)) + version: 4.3.4(vite@5.4.15(@types/node@22.14.1)(terser@5.39.0)) vite: specifier: ^5.3.4 - version: 5.4.15(@types/node@22.13.13)(terser@5.39.0) + version: 5.4.15(@types/node@22.14.1)(terser@5.39.0) examples/08-extensions/01-tiptap-arrow-conversion: dependencies: @@ -2662,10 +2671,10 @@ importers: version: 18.3.5(@types/react@18.3.20) '@vitejs/plugin-react': specifier: ^4.3.1 - version: 4.3.4(vite@5.4.15(@types/node@22.13.13)(terser@5.39.0)) + version: 4.3.4(vite@5.4.15(@types/node@22.14.1)(terser@5.39.0)) vite: specifier: ^5.3.4 - version: 5.4.15(@types/node@22.13.13)(terser@5.39.0) + version: 5.4.15(@types/node@22.14.1)(terser@5.39.0) examples/vanilla-js/react-vanilla-custom-blocks: dependencies: @@ -2699,10 +2708,10 @@ importers: version: 18.3.5(@types/react@18.3.20) '@vitejs/plugin-react': specifier: ^4.3.1 - version: 4.3.4(vite@5.4.15(@types/node@22.13.13)(terser@5.39.0)) + version: 4.3.4(vite@5.4.15(@types/node@22.14.1)(terser@5.39.0)) vite: specifier: ^5.3.4 - version: 5.4.15(@types/node@22.13.13)(terser@5.39.0) + version: 5.4.15(@types/node@22.14.1)(terser@5.39.0) examples/vanilla-js/react-vanilla-custom-inline-content: dependencies: @@ -2736,10 +2745,10 @@ importers: version: 18.3.5(@types/react@18.3.20) '@vitejs/plugin-react': specifier: ^4.3.1 - version: 4.3.4(vite@5.4.15(@types/node@22.13.13)(terser@5.39.0)) + version: 4.3.4(vite@5.4.15(@types/node@22.14.1)(terser@5.39.0)) vite: specifier: ^5.3.4 - version: 5.4.15(@types/node@22.13.13)(terser@5.39.0) + version: 5.4.15(@types/node@22.14.1)(terser@5.39.0) examples/vanilla-js/react-vanilla-custom-styles: dependencies: @@ -2773,10 +2782,10 @@ importers: version: 18.3.5(@types/react@18.3.20) '@vitejs/plugin-react': specifier: ^4.3.1 - version: 4.3.4(vite@5.4.15(@types/node@22.13.13)(terser@5.39.0)) + version: 4.3.4(vite@5.4.15(@types/node@22.14.1)(terser@5.39.0)) vite: specifier: ^5.3.4 - version: 5.4.15(@types/node@22.13.13)(terser@5.39.0) + version: 5.4.15(@types/node@22.14.1)(terser@5.39.0) packages/ariakit: dependencies: @@ -2804,7 +2813,7 @@ importers: version: 18.3.5(@types/react@18.3.20) '@vitejs/plugin-react': specifier: ^4.3.1 - version: 4.3.4(vite@5.4.15(@types/node@22.13.13)(terser@5.39.0)) + version: 4.3.4(vite@5.4.15(@types/node@22.14.1)(terser@5.39.0)) eslint: specifier: ^8.10.0 version: 8.57.1 @@ -2819,13 +2828,13 @@ importers: version: 5.8.2 vite: specifier: ^5.3.4 - version: 5.4.15(@types/node@22.13.13)(terser@5.39.0) + version: 5.4.15(@types/node@22.14.1)(terser@5.39.0) vite-plugin-eslint: specifier: ^1.8.1 - version: 1.8.1(eslint@8.57.1)(vite@5.4.15(@types/node@22.13.13)(terser@5.39.0)) + version: 1.8.1(eslint@8.57.1)(vite@5.4.15(@types/node@22.14.1)(terser@5.39.0)) vite-plugin-externalize-deps: specifier: ^0.8.0 - version: 0.8.0(vite@5.4.15(@types/node@22.13.13)(terser@5.39.0)) + version: 0.8.0(vite@5.4.15(@types/node@22.14.1)(terser@5.39.0)) packages/code-block: dependencies: @@ -2862,13 +2871,13 @@ importers: version: 5.8.2 vite: specifier: ^5.3.4 - version: 5.4.15(@types/node@22.13.13)(terser@5.39.0) + version: 5.4.15(@types/node@22.14.1)(terser@5.39.0) vite-plugin-eslint: specifier: ^1.8.1 - version: 1.8.1(eslint@8.57.1)(vite@5.4.15(@types/node@22.13.13)(terser@5.39.0)) + version: 1.8.1(eslint@8.57.1)(vite@5.4.15(@types/node@22.14.1)(terser@5.39.0)) vitest: specifier: ^2.0.3 - version: 2.1.9(@types/node@22.13.13)(@vitest/ui@2.1.9)(jsdom@25.0.1(canvas@2.11.2(encoding@0.1.13)))(terser@5.39.0) + version: 2.1.9(@types/node@22.14.1)(@vitest/ui@2.1.9)(jsdom@25.0.1(canvas@2.11.2(encoding@0.1.13)))(terser@5.39.0) packages/core: dependencies: @@ -3028,13 +3037,13 @@ importers: version: 5.8.2 vite: specifier: ^5.3.4 - version: 5.4.15(@types/node@22.13.13)(terser@5.39.0) + version: 5.4.15(@types/node@22.14.1)(terser@5.39.0) vite-plugin-eslint: specifier: ^1.8.1 - version: 1.8.1(eslint@8.57.1)(vite@5.4.15(@types/node@22.13.13)(terser@5.39.0)) + version: 1.8.1(eslint@8.57.1)(vite@5.4.15(@types/node@22.14.1)(terser@5.39.0)) vitest: specifier: ^2.0.3 - version: 2.1.9(@types/node@22.13.13)(@vitest/ui@2.1.9)(jsdom@25.0.1(canvas@2.11.2(encoding@0.1.13)))(terser@5.39.0) + version: 2.1.9(@types/node@22.14.1)(@vitest/ui@2.1.9)(jsdom@25.0.1(canvas@2.11.2(encoding@0.1.13)))(terser@5.39.0) packages/dev-scripts: dependencies: @@ -3070,6 +3079,28 @@ importers: specifier: ^5.3.3 version: 5.8.2 + packages/email: + dependencies: + '@react-email/components': + specifier: ^0.0.36 + version: 0.0.36(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + react: + specifier: ^19.1.0 + version: 19.1.0 + react-dom: + specifier: ^19.1.0 + version: 19.1.0(react@19.1.0) + devDependencies: + '@types/react': + specifier: ^19.1.2 + version: 19.1.2 + '@types/react-dom': + specifier: ^19.1.2 + version: 19.1.2(@types/react@19.1.2) + react-email: + specifier: ^4.0.7 + version: 4.0.7(@babel/core@7.26.10)(@opentelemetry/api@1.9.0)(@playwright/test@1.51.1)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + packages/mantine: dependencies: '@blocknote/core': @@ -3105,7 +3136,7 @@ importers: version: 18.3.5(@types/react@18.3.20) '@vitejs/plugin-react': specifier: ^4.3.1 - version: 4.3.4(vite@5.4.15(@types/node@22.13.13)(terser@5.39.0)) + version: 4.3.4(vite@5.4.15(@types/node@22.14.1)(terser@5.39.0)) eslint: specifier: ^8.10.0 version: 8.57.1 @@ -3120,13 +3151,13 @@ importers: version: 5.8.2 vite: specifier: ^5.3.4 - version: 5.4.15(@types/node@22.13.13)(terser@5.39.0) + version: 5.4.15(@types/node@22.14.1)(terser@5.39.0) vite-plugin-eslint: specifier: ^1.8.1 - version: 1.8.1(eslint@8.57.1)(vite@5.4.15(@types/node@22.13.13)(terser@5.39.0)) + version: 1.8.1(eslint@8.57.1)(vite@5.4.15(@types/node@22.14.1)(terser@5.39.0)) vite-plugin-externalize-deps: specifier: ^0.8.0 - version: 0.8.0(vite@5.4.15(@types/node@22.13.13)(terser@5.39.0)) + version: 0.8.0(vite@5.4.15(@types/node@22.14.1)(terser@5.39.0)) packages/react: dependencies: @@ -3178,7 +3209,7 @@ importers: version: 18.3.5(@types/react@18.3.20) '@vitejs/plugin-react': specifier: ^4.3.1 - version: 4.3.4(vite@5.4.15(@types/node@22.13.13)(terser@5.39.0)) + version: 4.3.4(vite@5.4.15(@types/node@22.14.1)(terser@5.39.0)) eslint: specifier: ^8.10.0 version: 8.57.1 @@ -3199,16 +3230,16 @@ importers: version: 5.8.2 vite: specifier: ^5.3.4 - version: 5.4.15(@types/node@22.13.13)(terser@5.39.0) + version: 5.4.15(@types/node@22.14.1)(terser@5.39.0) vite-plugin-eslint: specifier: ^1.8.1 - version: 1.8.1(eslint@8.57.1)(vite@5.4.15(@types/node@22.13.13)(terser@5.39.0)) + version: 1.8.1(eslint@8.57.1)(vite@5.4.15(@types/node@22.14.1)(terser@5.39.0)) vite-plugin-externalize-deps: specifier: ^0.8.0 - version: 0.8.0(vite@5.4.15(@types/node@22.13.13)(terser@5.39.0)) + version: 0.8.0(vite@5.4.15(@types/node@22.14.1)(terser@5.39.0)) vitest: specifier: ^2.0.3 - version: 2.1.9(@types/node@22.13.13)(@vitest/ui@2.1.9)(jsdom@25.0.1(canvas@2.11.2(encoding@0.1.13)))(terser@5.39.0) + version: 2.1.9(@types/node@22.14.1)(@vitest/ui@2.1.9)(jsdom@25.0.1(canvas@2.11.2(encoding@0.1.13)))(terser@5.39.0) packages/server-util: dependencies: @@ -3263,13 +3294,13 @@ importers: version: 5.8.2 vite: specifier: ^5.3.4 - version: 5.4.15(@types/node@22.13.13)(terser@5.39.0) + version: 5.4.15(@types/node@22.14.1)(terser@5.39.0) vite-plugin-eslint: specifier: ^1.8.1 - version: 1.8.1(eslint@8.57.1)(vite@5.4.15(@types/node@22.13.13)(terser@5.39.0)) + version: 1.8.1(eslint@8.57.1)(vite@5.4.15(@types/node@22.14.1)(terser@5.39.0)) vitest: specifier: ^2.0.3 - version: 2.1.9(@types/node@22.13.13)(@vitest/ui@2.1.9)(jsdom@25.0.1(canvas@2.11.2(encoding@0.1.13)))(terser@5.39.0) + version: 2.1.9(@types/node@22.14.1)(@vitest/ui@2.1.9)(jsdom@25.0.1(canvas@2.11.2(encoding@0.1.13)))(terser@5.39.0) packages/shadcn: dependencies: @@ -3424,13 +3455,13 @@ importers: version: 5.8.2 vite: specifier: ^5.3.4 - version: 5.4.15(@types/node@22.13.13)(terser@5.39.0) + version: 5.4.15(@types/node@22.14.1)(terser@5.39.0) vite-plugin-eslint: specifier: ^1.8.1 - version: 1.8.1(eslint@8.57.1)(vite@5.4.15(@types/node@22.13.13)(terser@5.39.0)) + version: 1.8.1(eslint@8.57.1)(vite@5.4.15(@types/node@22.14.1)(terser@5.39.0)) vitest: specifier: ^2.0.3 - version: 2.1.9(@types/node@22.13.13)(@vitest/ui@2.1.9)(jsdom@25.0.1(canvas@2.11.2(encoding@0.1.13)))(terser@5.39.0) + version: 2.1.9(@types/node@22.14.1)(@vitest/ui@2.1.9)(jsdom@25.0.1(canvas@2.11.2(encoding@0.1.13)))(terser@5.39.0) xml-formatter: specifier: ^3.6.3 version: 3.6.5 @@ -3497,13 +3528,13 @@ importers: version: 5.8.2 vite: specifier: ^5.3.4 - version: 5.4.15(@types/node@22.13.13)(terser@5.39.0) + version: 5.4.15(@types/node@22.14.1)(terser@5.39.0) vite-plugin-eslint: specifier: ^1.8.1 - version: 1.8.1(eslint@8.57.1)(vite@5.4.15(@types/node@22.13.13)(terser@5.39.0)) + version: 1.8.1(eslint@8.57.1)(vite@5.4.15(@types/node@22.14.1)(terser@5.39.0)) vitest: specifier: ^2.0.3 - version: 2.1.9(@types/node@22.13.13)(@vitest/ui@2.1.9)(jsdom@21.1.2(canvas@2.11.2(encoding@0.1.13)))(terser@5.39.0) + version: 2.1.9(@types/node@22.14.1)(@vitest/ui@2.1.9)(jsdom@21.1.2(canvas@2.11.2(encoding@0.1.13)))(terser@5.39.0) packages/xl-odt-exporter: dependencies: @@ -3543,13 +3574,13 @@ importers: version: 5.8.2 vite: specifier: ^5.3.4 - version: 5.4.15(@types/node@22.13.13)(terser@5.39.0) + version: 5.4.15(@types/node@22.14.1)(terser@5.39.0) vite-plugin-eslint: specifier: ^1.8.1 - version: 1.8.1(eslint@8.57.1)(vite@5.4.15(@types/node@22.13.13)(terser@5.39.0)) + version: 1.8.1(eslint@8.57.1)(vite@5.4.15(@types/node@22.14.1)(terser@5.39.0)) vitest: specifier: ^2.0.3 - version: 2.1.9(@types/node@22.13.13)(@vitest/ui@2.1.9)(jsdom@25.0.1(canvas@2.11.2(encoding@0.1.13)))(terser@5.39.0) + version: 2.1.9(@types/node@22.14.1)(@vitest/ui@2.1.9)(jsdom@25.0.1(canvas@2.11.2(encoding@0.1.13)))(terser@5.39.0) xml-formatter: specifier: ^3.6.3 version: 3.6.5 @@ -3613,13 +3644,13 @@ importers: version: 5.8.2 vite: specifier: ^5.3.4 - version: 5.4.15(@types/node@22.13.13)(terser@5.39.0) + version: 5.4.15(@types/node@22.14.1)(terser@5.39.0) vite-plugin-eslint: specifier: ^1.8.1 - version: 1.8.1(eslint@8.57.1)(vite@5.4.15(@types/node@22.13.13)(terser@5.39.0)) + version: 1.8.1(eslint@8.57.1)(vite@5.4.15(@types/node@22.14.1)(terser@5.39.0)) vitest: specifier: ^2.0.3 - version: 2.1.9(@types/node@22.13.13)(@vitest/ui@2.1.9)(jsdom@25.0.1(canvas@2.11.2(encoding@0.1.13)))(terser@5.39.0) + version: 2.1.9(@types/node@22.14.1)(@vitest/ui@2.1.9)(jsdom@25.0.1(canvas@2.11.2(encoding@0.1.13)))(terser@5.39.0) playground: dependencies: @@ -3761,7 +3792,7 @@ importers: version: 18.3.5(@types/react@18.3.20) '@vitejs/plugin-react': specifier: ^4.3.1 - version: 4.3.4(vite@5.4.15(@types/node@22.13.13)(terser@5.39.0)) + version: 4.3.4(vite@5.4.15(@types/node@22.14.1)(terser@5.39.0)) eslint: specifier: ^8.10.0 version: 8.57.1 @@ -3773,10 +3804,10 @@ importers: version: 0.2.6(rollup@4.37.0) vite: specifier: ^5.3.4 - version: 5.4.15(@types/node@22.13.13)(terser@5.39.0) + version: 5.4.15(@types/node@22.14.1)(terser@5.39.0) vite-plugin-eslint: specifier: ^1.8.1 - version: 1.8.1(eslint@8.57.1)(vite@5.4.15(@types/node@22.13.13)(terser@5.39.0)) + version: 1.8.1(eslint@8.57.1)(vite@5.4.15(@types/node@22.14.1)(terser@5.39.0)) shared: dependencies: @@ -4164,6 +4195,11 @@ packages: resolution: {integrity: sha512-U5eyP/CTFPuNE3qk+WZMxFkp/4zUzdceQlfzf7DdGdhp+Fezd7HD+i8Y24ZuTMKX3wQBld449jijbGq6OdGNQg==} engines: {node: '>=6.9.0'} + '@babel/parser@7.24.5': + resolution: {integrity: sha512-EOv5IK8arwh3LI47dz1b0tKUb/1uhHAnHJOrjgtQMIpu1uXd9mlFrJg9IUgGUgZ41Ch0K8REPTYpO7B76b4vJg==} + engines: {node: '>=6.0.0'} + hasBin: true + '@babel/parser@7.27.0': resolution: {integrity: sha512-iaepho73/2Pz7w2eMS0Q5f83+0RKI7i4xmiYeBmDzfRVbQtTOG7Ts0S4HzJVsTMGI9keU8rNfuZr8DKfSt7Yyg==} engines: {node: '>=6.0.0'} @@ -4701,6 +4737,10 @@ packages: resolution: {integrity: sha512-2ncevenBqXI6qRMukPlXwHKHchC7RyMuu4xv5JBXRfOGVcTy1mXCD12qrp7Jsoxll1EV3+9sE4GugBVRjT2jFA==} engines: {node: '>=6.9.0'} + '@babel/traverse@7.25.6': + resolution: {integrity: sha512-9Vrcx5ZW6UwK5tvqsj0nGpp/XzqthkT0dqIc9g1AdtygFToNtTF67XzYS//dm+SAK9cp3B9R4ZO/46p63SCjlQ==} + engines: {node: '>=6.9.0'} + '@babel/traverse@7.27.0': resolution: {integrity: sha512-19lYZFzYVQkkHkl4Cy4WrAVcqBkgvV2YM2TU3xG6DIwO7O3ecbDPfW3yM3bjAGcqcQHi+CCtjMR3dIEHxsd6bA==} engines: {node: '>=6.9.0'} @@ -4877,6 +4917,12 @@ packages: cpu: [ppc64] os: [aix] + '@esbuild/aix-ppc64@0.25.0': + resolution: {integrity: sha512-O7vun9Sf8DFjH2UtqK8Ku3LkquL9SZL8OLY1T5NZkA34+wG3OQF7cl4Ql8vdNzM6fzBbYfLaiRLIOZ+2FOCgBQ==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [aix] + '@esbuild/aix-ppc64@0.25.1': resolution: {integrity: sha512-kfYGy8IdzTGy+z0vFGvExZtxkFlA4zAxgKEahG9KE1ScBjpQnFsNOX8KTU5ojNru5ed5CVoJYXFtoxaq5nFbjQ==} engines: {node: '>=18'} @@ -4895,6 +4941,12 @@ packages: cpu: [arm64] os: [android] + '@esbuild/android-arm64@0.25.0': + resolution: {integrity: sha512-grvv8WncGjDSyUBjN9yHXNt+cq0snxXbDxy5pJtzMKGmmpPxeAmAhWxXI+01lU5rwZomDgD3kJwulEnhTRUd6g==} + engines: {node: '>=18'} + cpu: [arm64] + os: [android] + '@esbuild/android-arm64@0.25.1': resolution: {integrity: sha512-50tM0zCJW5kGqgG7fQ7IHvQOcAn9TKiVRuQ/lN0xR+T2lzEFvAi1ZcS8DiksFcEpf1t/GYOeOfCAgDHFpkiSmA==} engines: {node: '>=18'} @@ -4913,6 +4965,12 @@ packages: cpu: [arm] os: [android] + '@esbuild/android-arm@0.25.0': + resolution: {integrity: sha512-PTyWCYYiU0+1eJKmw21lWtC+d08JDZPQ5g+kFyxP0V+es6VPPSUhM6zk8iImp2jbV6GwjX4pap0JFbUQN65X1g==} + engines: {node: '>=18'} + cpu: [arm] + os: [android] + '@esbuild/android-arm@0.25.1': resolution: {integrity: sha512-dp+MshLYux6j/JjdqVLnMglQlFu+MuVeNrmT5nk6q07wNhCdSnB7QZj+7G8VMUGh1q+vj2Bq8kRsuyA00I/k+Q==} engines: {node: '>=18'} @@ -4931,6 +4989,12 @@ packages: cpu: [x64] os: [android] + '@esbuild/android-x64@0.25.0': + resolution: {integrity: sha512-m/ix7SfKG5buCnxasr52+LI78SQ+wgdENi9CqyCXwjVR2X4Jkz+BpC3le3AoBPYTC9NHklwngVXvbJ9/Akhrfg==} + engines: {node: '>=18'} + cpu: [x64] + os: [android] + '@esbuild/android-x64@0.25.1': resolution: {integrity: sha512-GCj6WfUtNldqUzYkN/ITtlhwQqGWu9S45vUXs7EIYf+7rCiiqH9bCloatO9VhxsL0Pji+PF4Lz2XXCES+Q8hDw==} engines: {node: '>=18'} @@ -4949,6 +5013,12 @@ packages: cpu: [arm64] os: [darwin] + '@esbuild/darwin-arm64@0.25.0': + resolution: {integrity: sha512-mVwdUb5SRkPayVadIOI78K7aAnPamoeFR2bT5nszFUZ9P8UpK4ratOdYbZZXYSqPKMHfS1wdHCJk1P1EZpRdvw==} + engines: {node: '>=18'} + cpu: [arm64] + os: [darwin] + '@esbuild/darwin-arm64@0.25.1': resolution: {integrity: sha512-5hEZKPf+nQjYoSr/elb62U19/l1mZDdqidGfmFutVUjjUZrOazAtwK+Kr+3y0C/oeJfLlxo9fXb1w7L+P7E4FQ==} engines: {node: '>=18'} @@ -4967,6 +5037,12 @@ packages: cpu: [x64] os: [darwin] + '@esbuild/darwin-x64@0.25.0': + resolution: {integrity: sha512-DgDaYsPWFTS4S3nWpFcMn/33ZZwAAeAFKNHNa1QN0rI4pUjgqf0f7ONmXf6d22tqTY+H9FNdgeaAa+YIFUn2Rg==} + engines: {node: '>=18'} + cpu: [x64] + os: [darwin] + '@esbuild/darwin-x64@0.25.1': resolution: {integrity: sha512-hxVnwL2Dqs3fM1IWq8Iezh0cX7ZGdVhbTfnOy5uURtao5OIVCEyj9xIzemDi7sRvKsuSdtCAhMKarxqtlyVyfA==} engines: {node: '>=18'} @@ -4985,6 +5061,12 @@ packages: cpu: [arm64] os: [freebsd] + '@esbuild/freebsd-arm64@0.25.0': + resolution: {integrity: sha512-VN4ocxy6dxefN1MepBx/iD1dH5K8qNtNe227I0mnTRjry8tj5MRk4zprLEdG8WPyAPb93/e4pSgi1SoHdgOa4w==} + engines: {node: '>=18'} + cpu: [arm64] + os: [freebsd] + '@esbuild/freebsd-arm64@0.25.1': resolution: {integrity: sha512-1MrCZs0fZa2g8E+FUo2ipw6jw5qqQiH+tERoS5fAfKnRx6NXH31tXBKI3VpmLijLH6yriMZsxJtaXUyFt/8Y4A==} engines: {node: '>=18'} @@ -5003,6 +5085,12 @@ packages: cpu: [x64] os: [freebsd] + '@esbuild/freebsd-x64@0.25.0': + resolution: {integrity: sha512-mrSgt7lCh07FY+hDD1TxiTyIHyttn6vnjesnPoVDNmDfOmggTLXRv8Id5fNZey1gl/V2dyVK1VXXqVsQIiAk+A==} + engines: {node: '>=18'} + cpu: [x64] + os: [freebsd] + '@esbuild/freebsd-x64@0.25.1': resolution: {integrity: sha512-0IZWLiTyz7nm0xuIs0q1Y3QWJC52R8aSXxe40VUxm6BB1RNmkODtW6LHvWRrGiICulcX7ZvyH6h5fqdLu4gkww==} engines: {node: '>=18'} @@ -5021,6 +5109,12 @@ packages: cpu: [arm64] os: [linux] + '@esbuild/linux-arm64@0.25.0': + resolution: {integrity: sha512-9QAQjTWNDM/Vk2bgBl17yWuZxZNQIF0OUUuPZRKoDtqF2k4EtYbpyiG5/Dk7nqeK6kIJWPYldkOcBqjXjrUlmg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [linux] + '@esbuild/linux-arm64@0.25.1': resolution: {integrity: sha512-jaN3dHi0/DDPelk0nLcXRm1q7DNJpjXy7yWaWvbfkPvI+7XNSc/lDOnCLN7gzsyzgu6qSAmgSvP9oXAhP973uQ==} engines: {node: '>=18'} @@ -5039,6 +5133,12 @@ packages: cpu: [arm] os: [linux] + '@esbuild/linux-arm@0.25.0': + resolution: {integrity: sha512-vkB3IYj2IDo3g9xX7HqhPYxVkNQe8qTK55fraQyTzTX/fxaDtXiEnavv9geOsonh2Fd2RMB+i5cbhu2zMNWJwg==} + engines: {node: '>=18'} + cpu: [arm] + os: [linux] + '@esbuild/linux-arm@0.25.1': resolution: {integrity: sha512-NdKOhS4u7JhDKw9G3cY6sWqFcnLITn6SqivVArbzIaf3cemShqfLGHYMx8Xlm/lBit3/5d7kXvriTUGa5YViuQ==} engines: {node: '>=18'} @@ -5057,6 +5157,12 @@ packages: cpu: [ia32] os: [linux] + '@esbuild/linux-ia32@0.25.0': + resolution: {integrity: sha512-43ET5bHbphBegyeqLb7I1eYn2P/JYGNmzzdidq/w0T8E2SsYL1U6un2NFROFRg1JZLTzdCoRomg8Rvf9M6W6Gg==} + engines: {node: '>=18'} + cpu: [ia32] + os: [linux] + '@esbuild/linux-ia32@0.25.1': resolution: {integrity: sha512-OJykPaF4v8JidKNGz8c/q1lBO44sQNUQtq1KktJXdBLn1hPod5rE/Hko5ugKKZd+D2+o1a9MFGUEIUwO2YfgkQ==} engines: {node: '>=18'} @@ -5075,6 +5181,12 @@ packages: cpu: [loong64] os: [linux] + '@esbuild/linux-loong64@0.25.0': + resolution: {integrity: sha512-fC95c/xyNFueMhClxJmeRIj2yrSMdDfmqJnyOY4ZqsALkDrrKJfIg5NTMSzVBr5YW1jf+l7/cndBfP3MSDpoHw==} + engines: {node: '>=18'} + cpu: [loong64] + os: [linux] + '@esbuild/linux-loong64@0.25.1': resolution: {integrity: sha512-nGfornQj4dzcq5Vp835oM/o21UMlXzn79KobKlcs3Wz9smwiifknLy4xDCLUU0BWp7b/houtdrgUz7nOGnfIYg==} engines: {node: '>=18'} @@ -5093,6 +5205,12 @@ packages: cpu: [mips64el] os: [linux] + '@esbuild/linux-mips64el@0.25.0': + resolution: {integrity: sha512-nkAMFju7KDW73T1DdH7glcyIptm95a7Le8irTQNO/qtkoyypZAnjchQgooFUDQhNAy4iu08N79W4T4pMBwhPwQ==} + engines: {node: '>=18'} + cpu: [mips64el] + os: [linux] + '@esbuild/linux-mips64el@0.25.1': resolution: {integrity: sha512-1osBbPEFYwIE5IVB/0g2X6i1qInZa1aIoj1TdL4AaAb55xIIgbg8Doq6a5BzYWgr+tEcDzYH67XVnTmUzL+nXg==} engines: {node: '>=18'} @@ -5111,6 +5229,12 @@ packages: cpu: [ppc64] os: [linux] + '@esbuild/linux-ppc64@0.25.0': + resolution: {integrity: sha512-NhyOejdhRGS8Iwv+KKR2zTq2PpysF9XqY+Zk77vQHqNbo/PwZCzB5/h7VGuREZm1fixhs4Q/qWRSi5zmAiO4Fw==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [linux] + '@esbuild/linux-ppc64@0.25.1': resolution: {integrity: sha512-/6VBJOwUf3TdTvJZ82qF3tbLuWsscd7/1w+D9LH0W/SqUgM5/JJD0lrJ1fVIfZsqB6RFmLCe0Xz3fmZc3WtyVg==} engines: {node: '>=18'} @@ -5129,6 +5253,12 @@ packages: cpu: [riscv64] os: [linux] + '@esbuild/linux-riscv64@0.25.0': + resolution: {integrity: sha512-5S/rbP5OY+GHLC5qXp1y/Mx//e92L1YDqkiBbO9TQOvuFXM+iDqUNG5XopAnXoRH3FjIUDkeGcY1cgNvnXp/kA==} + engines: {node: '>=18'} + cpu: [riscv64] + os: [linux] + '@esbuild/linux-riscv64@0.25.1': resolution: {integrity: sha512-nSut/Mx5gnilhcq2yIMLMe3Wl4FK5wx/o0QuuCLMtmJn+WeWYoEGDN1ipcN72g1WHsnIbxGXd4i/MF0gTcuAjQ==} engines: {node: '>=18'} @@ -5147,6 +5277,12 @@ packages: cpu: [s390x] os: [linux] + '@esbuild/linux-s390x@0.25.0': + resolution: {integrity: sha512-XM2BFsEBz0Fw37V0zU4CXfcfuACMrppsMFKdYY2WuTS3yi8O1nFOhil/xhKTmE1nPmVyvQJjJivgDT+xh8pXJA==} + engines: {node: '>=18'} + cpu: [s390x] + os: [linux] + '@esbuild/linux-s390x@0.25.1': resolution: {integrity: sha512-cEECeLlJNfT8kZHqLarDBQso9a27o2Zd2AQ8USAEoGtejOrCYHNtKP8XQhMDJMtthdF4GBmjR2au3x1udADQQQ==} engines: {node: '>=18'} @@ -5165,12 +5301,24 @@ packages: cpu: [x64] os: [linux] + '@esbuild/linux-x64@0.25.0': + resolution: {integrity: sha512-9yl91rHw/cpwMCNytUDxwj2XjFpxML0y9HAOH9pNVQDpQrBxHy01Dx+vaMu0N1CKa/RzBD2hB4u//nfc+Sd3Cw==} + engines: {node: '>=18'} + cpu: [x64] + os: [linux] + '@esbuild/linux-x64@0.25.1': resolution: {integrity: sha512-xbfUhu/gnvSEg+EGovRc+kjBAkrvtk38RlerAzQxvMzlB4fXpCFCeUAYzJvrnhFtdeyVCDANSjJvOvGYoeKzFA==} engines: {node: '>=18'} cpu: [x64] os: [linux] + '@esbuild/netbsd-arm64@0.25.0': + resolution: {integrity: sha512-RuG4PSMPFfrkH6UwCAqBzauBWTygTvb1nxWasEJooGSJ/NwRw7b2HOwyRTQIU97Hq37l3npXoZGYMy3b3xYvPw==} + engines: {node: '>=18'} + cpu: [arm64] + os: [netbsd] + '@esbuild/netbsd-arm64@0.25.1': resolution: {integrity: sha512-O96poM2XGhLtpTh+s4+nP7YCCAfb4tJNRVZHfIE7dgmax+yMP2WgMd2OecBuaATHKTHsLWHQeuaxMRnCsH8+5g==} engines: {node: '>=18'} @@ -5189,12 +5337,24 @@ packages: cpu: [x64] os: [netbsd] + '@esbuild/netbsd-x64@0.25.0': + resolution: {integrity: sha512-jl+qisSB5jk01N5f7sPCsBENCOlPiS/xptD5yxOx2oqQfyourJwIKLRA2yqWdifj3owQZCL2sn6o08dBzZGQzA==} + engines: {node: '>=18'} + cpu: [x64] + os: [netbsd] + '@esbuild/netbsd-x64@0.25.1': resolution: {integrity: sha512-X53z6uXip6KFXBQ+Krbx25XHV/NCbzryM6ehOAeAil7X7oa4XIq+394PWGnwaSQ2WRA0KI6PUO6hTO5zeF5ijA==} engines: {node: '>=18'} cpu: [x64] os: [netbsd] + '@esbuild/openbsd-arm64@0.25.0': + resolution: {integrity: sha512-21sUNbq2r84YE+SJDfaQRvdgznTD8Xc0oc3p3iW/a1EVWeNj/SdUCbm5U0itZPQYRuRTW20fPMWMpcrciH2EJw==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openbsd] + '@esbuild/openbsd-arm64@0.25.1': resolution: {integrity: sha512-Na9T3szbXezdzM/Kfs3GcRQNjHzM6GzFBeU1/6IV/npKP5ORtp9zbQjvkDJ47s6BCgaAZnnnu/cY1x342+MvZg==} engines: {node: '>=18'} @@ -5213,6 +5373,12 @@ packages: cpu: [x64] os: [openbsd] + '@esbuild/openbsd-x64@0.25.0': + resolution: {integrity: sha512-2gwwriSMPcCFRlPlKx3zLQhfN/2WjJ2NSlg5TKLQOJdV0mSxIcYNTMhk3H3ulL/cak+Xj0lY1Ym9ysDV1igceg==} + engines: {node: '>=18'} + cpu: [x64] + os: [openbsd] + '@esbuild/openbsd-x64@0.25.1': resolution: {integrity: sha512-T3H78X2h1tszfRSf+txbt5aOp/e7TAz3ptVKu9Oyir3IAOFPGV6O9c2naym5TOriy1l0nNf6a4X5UXRZSGX/dw==} engines: {node: '>=18'} @@ -5231,6 +5397,12 @@ packages: cpu: [x64] os: [sunos] + '@esbuild/sunos-x64@0.25.0': + resolution: {integrity: sha512-bxI7ThgLzPrPz484/S9jLlvUAHYMzy6I0XiU1ZMeAEOBcS0VePBFxh1JjTQt3Xiat5b6Oh4x7UC7IwKQKIJRIg==} + engines: {node: '>=18'} + cpu: [x64] + os: [sunos] + '@esbuild/sunos-x64@0.25.1': resolution: {integrity: sha512-2H3RUvcmULO7dIE5EWJH8eubZAI4xw54H1ilJnRNZdeo8dTADEZ21w6J22XBkXqGJbe0+wnNJtw3UXRoLJnFEg==} engines: {node: '>=18'} @@ -5249,6 +5421,12 @@ packages: cpu: [arm64] os: [win32] + '@esbuild/win32-arm64@0.25.0': + resolution: {integrity: sha512-ZUAc2YK6JW89xTbXvftxdnYy3m4iHIkDtK3CLce8wg8M2L+YZhIvO1DKpxrd0Yr59AeNNkTiic9YLf6FTtXWMw==} + engines: {node: '>=18'} + cpu: [arm64] + os: [win32] + '@esbuild/win32-arm64@0.25.1': resolution: {integrity: sha512-GE7XvrdOzrb+yVKB9KsRMq+7a2U/K5Cf/8grVFRAGJmfADr/e/ODQ134RK2/eeHqYV5eQRFxb1hY7Nr15fv1NQ==} engines: {node: '>=18'} @@ -5267,6 +5445,12 @@ packages: cpu: [ia32] os: [win32] + '@esbuild/win32-ia32@0.25.0': + resolution: {integrity: sha512-eSNxISBu8XweVEWG31/JzjkIGbGIJN/TrRoiSVZwZ6pkC6VX4Im/WV2cz559/TXLcYbcrDN8JtKgd9DJVIo8GA==} + engines: {node: '>=18'} + cpu: [ia32] + os: [win32] + '@esbuild/win32-ia32@0.25.1': resolution: {integrity: sha512-uOxSJCIcavSiT6UnBhBzE8wy3n0hOkJsBOzy7HDAuTDE++1DJMRRVCPGisULScHL+a/ZwdXPpXD3IyFKjA7K8A==} engines: {node: '>=18'} @@ -5285,6 +5469,12 @@ packages: cpu: [x64] os: [win32] + '@esbuild/win32-x64@0.25.0': + resolution: {integrity: sha512-ZENoHJBxA20C2zFzh6AI4fT6RraMzjYw4xKWemRTRmRVtN9c5DcH9r/f2ihEkMjOW5eGgrwCslG/+Y/3bL+DHQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [win32] + '@esbuild/win32-x64@0.25.1': resolution: {integrity: sha512-Y1EQdcfwMSeQN/ujR5VayLOJ1BHaK+ssyk0AEzPjC+t1lITgsnccPqFjb6V+LsTp/9Iov4ysfjxLaGJ9RPtkVg==} engines: {node: '>=18'} @@ -6193,11 +6383,11 @@ packages: peerDependencies: next: ^15.0.0 || ^15.2.0-canary.* - '@polar-sh/sdk@0.32.10': - resolution: {integrity: sha512-k7og3L1RP7kTRFVSxiVF4GIkTy/JQwfUY4D1aqSEnj3OtR13NjHsAW2Rb6bEJDuws2/bzfAVQvbQTxf+VsmK9A==} + '@polar-sh/sdk@0.32.11': + resolution: {integrity: sha512-GmMDrWyJJnM45rByMRkY8U8DYbL2ggJNohhTc/9naMlGHnP3+RRgIG9IG6yxuXfQ1wljKyoViHAWCAGCvS3DPA==} hasBin: true peerDependencies: - '@modelcontextprotocol/sdk': ^1.5.0 + '@modelcontextprotocol/sdk': '>=1.5.0 <1.10.0' zod: '>= 3' peerDependenciesMeta: '@modelcontextprotocol/sdk': @@ -6603,6 +6793,131 @@ packages: '@radix-ui/rect@1.1.0': resolution: {integrity: sha512-A9+lCBZoaMJlVKcRBz2YByCG+Cp2t6nAnMnNba+XiWxnj6r4JUFqfsgwocMBZU9LPtdxC6wB56ySYpc7LQIoJg==} + '@react-email/body@0.0.11': + resolution: {integrity: sha512-ZSD2SxVSgUjHGrB0Wi+4tu3MEpB4fYSbezsFNEJk2xCWDBkFiOeEsjTmR5dvi+CxTK691hQTQlHv0XWuP7ENTg==} + peerDependencies: + react: ^18.0 || ^19.0 || ^19.0.0-rc + + '@react-email/button@0.0.19': + resolution: {integrity: sha512-HYHrhyVGt7rdM/ls6FuuD6XE7fa7bjZTJqB2byn6/oGsfiEZaogY77OtoLL/mrQHjHjZiJadtAMSik9XLcm7+A==} + engines: {node: '>=18.0.0'} + peerDependencies: + react: ^18.0 || ^19.0 || ^19.0.0-rc + + '@react-email/code-block@0.0.12': + resolution: {integrity: sha512-Faw3Ij9+/Qwq6moWaeHnV8Hn7ekc/EqyAzPi6yUar21dhcqYugCC4Da1x4d9nA9zC0H9KU3lYVJczh8D3cA+Eg==} + engines: {node: '>=18.0.0'} + peerDependencies: + react: ^18.0 || ^19.0 || ^19.0.0-rc + + '@react-email/code-inline@0.0.5': + resolution: {integrity: sha512-MmAsOzdJpzsnY2cZoPHFPk6uDO/Ncpb4Kh1hAt9UZc1xOW3fIzpe1Pi9y9p6wwUmpaeeDalJxAxH6/fnTquinA==} + engines: {node: '>=18.0.0'} + peerDependencies: + react: ^18.0 || ^19.0 || ^19.0.0-rc + + '@react-email/column@0.0.13': + resolution: {integrity: sha512-Lqq17l7ShzJG/d3b1w/+lVO+gp2FM05ZUo/nW0rjxB8xBICXOVv6PqjDnn3FXKssvhO5qAV20lHM6S+spRhEwQ==} + engines: {node: '>=18.0.0'} + peerDependencies: + react: ^18.0 || ^19.0 || ^19.0.0-rc + + '@react-email/components@0.0.36': + resolution: {integrity: sha512-VMh+OQplAnG8JMLlJjdnjt+ThJZ+JVkp0q2YMS2NEz+T88N22bLD2p7DZO0QgtNaKgumOhJI/0a2Q7VzCrwu5g==} + engines: {node: '>=18.0.0'} + peerDependencies: + react: ^18.0 || ^19.0 || ^19.0.0-rc + + '@react-email/container@0.0.15': + resolution: {integrity: sha512-Qo2IQo0ru2kZq47REmHW3iXjAQaKu4tpeq/M8m1zHIVwKduL2vYOBQWbC2oDnMtWPmkBjej6XxgtZByxM6cCFg==} + engines: {node: '>=18.0.0'} + peerDependencies: + react: ^18.0 || ^19.0 || ^19.0.0-rc + + '@react-email/font@0.0.9': + resolution: {integrity: sha512-4zjq23oT9APXkerqeslPH3OZWuh5X4crHK6nx82mVHV2SrLba8+8dPEnWbaACWTNjOCbcLIzaC9unk7Wq2MIXw==} + peerDependencies: + react: ^18.0 || ^19.0 || ^19.0.0-rc + + '@react-email/head@0.0.12': + resolution: {integrity: sha512-X2Ii6dDFMF+D4niNwMAHbTkeCjlYYnMsd7edXOsi0JByxt9wNyZ9EnhFiBoQdqkE+SMDcu8TlNNttMrf5sJeMA==} + engines: {node: '>=18.0.0'} + peerDependencies: + react: ^18.0 || ^19.0 || ^19.0.0-rc + + '@react-email/heading@0.0.15': + resolution: {integrity: sha512-xF2GqsvBrp/HbRHWEfOgSfRFX+Q8I5KBEIG5+Lv3Vb2R/NYr0s8A5JhHHGf2pWBMJdbP4B2WHgj/VUrhy8dkIg==} + engines: {node: '>=18.0.0'} + peerDependencies: + react: ^18.0 || ^19.0 || ^19.0.0-rc + + '@react-email/hr@0.0.11': + resolution: {integrity: sha512-S1gZHVhwOsd1Iad5IFhpfICwNPMGPJidG/Uysy1AwmspyoAP5a4Iw3OWEpINFdgh9MHladbxcLKO2AJO+cA9Lw==} + engines: {node: '>=18.0.0'} + peerDependencies: + react: ^18.0 || ^19.0 || ^19.0.0-rc + + '@react-email/html@0.0.11': + resolution: {integrity: sha512-qJhbOQy5VW5qzU74AimjAR9FRFQfrMa7dn4gkEXKMB/S9xZN8e1yC1uA9C15jkXI/PzmJ0muDIWmFwatm5/+VA==} + engines: {node: '>=18.0.0'} + peerDependencies: + react: ^18.0 || ^19.0 || ^19.0.0-rc + + '@react-email/img@0.0.11': + resolution: {integrity: sha512-aGc8Y6U5C3igoMaqAJKsCpkbm1XjguQ09Acd+YcTKwjnC2+0w3yGUJkjWB2vTx4tN8dCqQCXO8FmdJpMfOA9EQ==} + engines: {node: '>=18.0.0'} + peerDependencies: + react: ^18.0 || ^19.0 || ^19.0.0-rc + + '@react-email/link@0.0.12': + resolution: {integrity: sha512-vF+xxQk2fGS1CN7UPQDbzvcBGfffr+GjTPNiWM38fhBfsLv6A/YUfaqxWlmL7zLzVmo0K2cvvV9wxlSyNba1aQ==} + engines: {node: '>=18.0.0'} + peerDependencies: + react: ^18.0 || ^19.0 || ^19.0.0-rc + + '@react-email/markdown@0.0.14': + resolution: {integrity: sha512-5IsobCyPkb4XwnQO8uFfGcNOxnsg3311GRXhJ3uKv51P7Jxme4ycC/MITnwIZ10w2zx7HIyTiqVzTj4XbuIHbg==} + engines: {node: '>=18.0.0'} + peerDependencies: + react: ^18.0 || ^19.0 || ^19.0.0-rc + + '@react-email/preview@0.0.12': + resolution: {integrity: sha512-g/H5fa9PQPDK6WUEG7iTlC19sAktI23qyoiJtMLqQiXFCfWeQMhqjLGKeLSKkfzszqmfJCjZtpSiKtBoOdxp3Q==} + engines: {node: '>=18.0.0'} + peerDependencies: + react: ^18.0 || ^19.0 || ^19.0.0-rc + + '@react-email/render@1.0.6': + resolution: {integrity: sha512-zNueW5Wn/4jNC1c5LFgXzbUdv5Lhms+FWjOvWAhal7gx5YVf0q6dPJ0dnR70+ifo59gcMLwCZEaTS9EEuUhKvQ==} + engines: {node: '>=18.0.0'} + peerDependencies: + react: ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^18.0 || ^19.0 || ^19.0.0-rc + + '@react-email/row@0.0.12': + resolution: {integrity: sha512-HkCdnEjvK3o+n0y0tZKXYhIXUNPDx+2vq1dJTmqappVHXS5tXS6W5JOPZr5j+eoZ8gY3PShI2LWj5rWF7ZEtIQ==} + engines: {node: '>=18.0.0'} + peerDependencies: + react: ^18.0 || ^19.0 || ^19.0.0-rc + + '@react-email/section@0.0.16': + resolution: {integrity: sha512-FjqF9xQ8FoeUZYKSdt8sMIKvoT9XF8BrzhT3xiFKdEMwYNbsDflcjfErJe3jb7Wj/es/lKTbV5QR1dnLzGpL3w==} + engines: {node: '>=18.0.0'} + peerDependencies: + react: ^18.0 || ^19.0 || ^19.0.0-rc + + '@react-email/tailwind@1.0.4': + resolution: {integrity: sha512-tJdcusncdqgvTUYZIuhNC6LYTfL9vNTSQpwWdTCQhQ1lsrNCEE4OKCSdzSV3S9F32pi0i0xQ+YPJHKIzGjdTSA==} + engines: {node: '>=18.0.0'} + peerDependencies: + react: ^18.0 || ^19.0 || ^19.0.0-rc + + '@react-email/text@0.1.1': + resolution: {integrity: sha512-Zo9tSEzkO3fODLVH1yVhzVCiwETfeEL5wU93jXKWo2DHoMuiZ9Iabaso3T0D0UjhrCB1PBMeq2YiejqeToTyIQ==} + engines: {node: '>=18.0.0'} + peerDependencies: + react: ^18.0 || ^19.0 || ^19.0.0-rc + '@react-pdf/fns@3.1.2': resolution: {integrity: sha512-qTKGUf0iAMGg2+OsUcp9ffKnKi41RukM/zYIWMDJ4hRVYSr89Q7e3wSDW/Koqx3ea3Uy/z3h2y3wPX6Bdfxk6g==} @@ -6785,6 +7100,9 @@ packages: '@rushstack/eslint-patch@1.11.0': resolution: {integrity: sha512-zxnHvoMQVqewTJr/W4pKjF0bMGiKJv1WX7bSrkl46Hg0QjESbzBROWK0Wg4RphzSOS5Jiy7eFimmM3UgMrMZbQ==} + '@selderee/plugin-htmlparser2@0.11.0': + resolution: {integrity: sha512-P33hHGdldxGabLFjPPpaTxVolMrzrcegejx+0GxjrIb9Zv48D8yAIA/QTDR2dFl7Uz7urX8aX6+5bCZslr+gWQ==} + '@sentry-internal/browser-utils@9.4.0': resolution: {integrity: sha512-huoSluJhyhN/EFXpRhUIFg0DQICrE9bCGZ4TBSG7l0zOVm3i957W5pUiE5qQkR7wmAfCuJ8Dh/tgo4ngSA21Gg==} engines: {node: '>=18'} @@ -7158,6 +7476,9 @@ packages: resolution: {integrity: sha512-JtaY3FxmD+te+KSI2FJuEcfNC9T/DGGVf551babM7fAaXhjJUt7oSYurH1Devxd2+BOSUACCgt3buinx4UnmEA==} engines: {node: '>=18.0.0'} + '@socket.io/component-emitter@3.1.2': + resolution: {integrity: sha512-9BCxFwvbGg/RsZK9tjXd8s4UcwR0MWeFQ1XEKIQVVvAGJyINdrqKMcTRyLoK8Rse1GjzLV9cwjWV1olXRWEXVA==} + '@stablelib/base64@1.0.1': resolution: {integrity: sha512-1bnPQqSxSuc3Ii6MhBysoWCg58j97aUjuCSZrGSmDxNqtytIi0k8utUenAwTZN4V5mXXYGsVUI9zeBqy+jBOSQ==} @@ -7361,6 +7682,9 @@ packages: '@types/cookie@0.6.0': resolution: {integrity: sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA==} + '@types/cors@2.8.17': + resolution: {integrity: sha512-8CGDvrBj1zgo2qE+oS3pOCyYNqCPryMWY2bGfwA0dcfopWGgxs+78df0Rs3rc9THP4JkOhLsAa+15VdpAqkcUA==} + '@types/d3-scale-chromatic@3.1.0': resolution: {integrity: sha512-iWMJgwkK7yTRmWqRB5plb1kadXyQ5Sj8V/zYlFGMUBbIPKQScw+Dku9cAAMgJG+z5GYDoMjWGLVOvjghDEFnKQ==} @@ -7475,6 +7799,9 @@ packages: '@types/node@22.13.13': resolution: {integrity: sha512-ClsL5nMwKaBRwPcCvH8E7+nU4GxHVx1axNvMZTFHMEfNI7oahimt26P5zjVCRrjiIWj6YFXfE1v3dEp94wLcGQ==} + '@types/node@22.14.1': + resolution: {integrity: sha512-u0HuPQwe/dHrItgHHpmw3N2fYCR6x4ivMNbPHRkBVP4CvN+kiRrKHWk3i8tXiO/joPwXLMYvF9TTF0eqgHIuOw==} + '@types/nodemailer@6.4.17': resolution: {integrity: sha512-I9CCaIp6DTldEg7vyUTZi8+9Vo0hi1/T8gv3C89yk1rSAAzoKQ8H8ki/jBYJSFoH/BisgLP8tkZMlQ91CIquww==} @@ -7498,6 +7825,11 @@ packages: peerDependencies: '@types/react': ^18.0.0 + '@types/react-dom@19.1.2': + resolution: {integrity: sha512-XGJkWF41Qq305SKWEILa1O8vzhb3aOo3ogBlSmiqNko/WmRb6QIaweuZCXjKygVDXpzXb5wyxKTSOsmkuqj+Qw==} + peerDependencies: + '@types/react': ^19.0.0 + '@types/react-transition-group@4.4.12': resolution: {integrity: sha512-8TV6R3h2j7a91c+1DXdJi3Syo69zzIZbz7Lg5tORM5LEJG7X/E6a1V3drRyBRZq7/utz7A+c4OgYLiLcYGHG6w==} peerDependencies: @@ -7506,8 +7838,8 @@ packages: '@types/react@18.3.20': resolution: {integrity: sha512-IPaCZN7PShZK/3t6Q87pfTkRm6oLTd4vztyoj+cbHUF1g3FfVb2tFIL79uCRKEfv16AhqDMBywP2VW3KIZUvcg==} - '@types/react@19.0.12': - resolution: {integrity: sha512-V6Ar115dBDrjbtXSrS+/Oruobc+qVbbUxDFC1RSbRqLt5SYvxxyIDrSC85RWml54g+jfNeEMZhEj7wW07ONQhA==} + '@types/react@19.1.2': + resolution: {integrity: sha512-oxLPMytKchWGbnQM9O7D67uPa9paTNxO7jVoNMXgkkErULBPhPARCfkKL9ytcIJJRGjbsVwW4ugJzyFFvm/Tiw==} '@types/retry@0.12.2': resolution: {integrity: sha512-XISRgDJ2Tc5q4TRqvgJtzsRkFYNJzZrhTdtMoGVBttwzzQJkPnS3WWTFc7kuDRoPtPakl+T+OfdEUjYJj7Jbow==} @@ -8224,6 +8556,10 @@ packages: base64-js@1.5.1: resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} + base64id@2.0.0: + resolution: {integrity: sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog==} + engines: {node: ^4.5.0 || >= 5.9} + better-auth@1.2.7: resolution: {integrity: sha512-2hCB263GSrgetsMUZw8vv9O1e4S4AlYJW3P4e8bX9u3Q3idv4u9BzDFCblpTLuL4YjYovghMCN0vurAsctXOAQ==} @@ -8386,6 +8722,10 @@ packages: resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==} engines: {node: '>= 8.10.0'} + chokidar@4.0.3: + resolution: {integrity: sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==} + engines: {node: '>= 14.16.0'} + chownr@1.1.4: resolution: {integrity: sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==} @@ -8498,6 +8838,10 @@ packages: comma-separated-tokens@2.0.3: resolution: {integrity: sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==} + commander@11.1.0: + resolution: {integrity: sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ==} + engines: {node: '>=16'} + commander@2.20.3: resolution: {integrity: sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==} @@ -8565,6 +8909,10 @@ packages: core-util-is@1.0.3: resolution: {integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==} + cors@2.8.5: + resolution: {integrity: sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==} + engines: {node: '>= 0.10'} + cose-base@1.0.3: resolution: {integrity: sha512-s9whTXInMSgAp/NVXVNuVxVKzGH2qck3aQlVHxDCdAEPgtMKwc4Wq6/QKhgdEdgbLSi9rBTAcPoRa6JpiG4ksg==} @@ -8804,6 +9152,10 @@ packages: debounce@1.2.1: resolution: {integrity: sha512-XRRe6Glud4rd/ZGQfiV1ruXSfbvfJedlV9Y6zOlP+2K04vBYiJEte6stfFkCP03aMnY5tsipamumUjL14fofug==} + debounce@2.0.0: + resolution: {integrity: sha512-xRetU6gL1VJbs85Mc4FoEGSjQxzpdxRyFhe3lmWFyy2EzydIcD4xzUvRJMD+NPDfMwKNhxa3PvsIOU32luIWeA==} + engines: {node: '>=18'} + debug@2.6.9: resolution: {integrity: sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==} peerDependencies: @@ -8820,6 +9172,15 @@ packages: supports-color: optional: true + debug@4.3.7: + resolution: {integrity: sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + debug@4.4.0: resolution: {integrity: sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==} engines: {node: '>=6.0'} @@ -8854,6 +9215,10 @@ packages: deep-is@0.1.4: resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} + deepmerge@4.3.1: + resolution: {integrity: sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==} + engines: {node: '>=0.10.0'} + defaults@1.0.4: resolution: {integrity: sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==} @@ -8944,14 +9309,27 @@ packages: dom-helpers@5.2.1: resolution: {integrity: sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==} + dom-serializer@2.0.0: + resolution: {integrity: sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==} + + domelementtype@2.3.0: + resolution: {integrity: sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==} + domexception@4.0.0: resolution: {integrity: sha512-A2is4PLG+eeSfoTMA95/s4pvAoSo2mKtiM5jlHkAVewmiO8ISFTFKZjH7UAM1Atli/OT/7JHOrJRJiMKUZKYBw==} engines: {node: '>=12'} deprecated: Use your platform's native DOMException instead + domhandler@5.0.3: + resolution: {integrity: sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==} + engines: {node: '>= 4'} + dompurify@3.1.6: resolution: {integrity: sha512-cTOAhc36AalkjtBpfG6O8JimdTMWNXjiePT2xQH/ppBGi/4uIpmj8eKyIkMJErXWARyINV/sB38yf8JCLF5pbQ==} + domutils@3.2.2: + resolution: {integrity: sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==} + dotenv-expand@11.0.7: resolution: {integrity: sha512-zIHwmZPRshsCdpMDyVsqGmgyP0yT8GAgXUnkdAoJisxvf33k7yO6OuoKmcTGuXPWSsm8Oh88nZicRLA9Y0rUeA==} engines: {node: '>=12'} @@ -9006,6 +9384,14 @@ packages: end-of-stream@1.4.4: resolution: {integrity: sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==} + engine.io-parser@5.2.3: + resolution: {integrity: sha512-HqD3yTBfnBxIrbnM1DoD6Pcq8NECnh8d4As1Qgh0z5Gg3jRRIqijury0CL3ghu/edArpUYiYqQiDUQBIs4np3Q==} + engines: {node: '>=10.0.0'} + + engine.io@6.6.4: + resolution: {integrity: sha512-ZCkIjSYNDyGn0R6ewHDtXgns/Zre/NT6Agvq1/WobF7JXgFff4SeDroKiCO3fNJreU9YG429Sc81o4w5ok/W5g==} + engines: {node: '>=10.2.0'} + enhanced-resolve@5.18.1: resolution: {integrity: sha512-ZSW3ma5GkcQBIpwZTSRAI8N71Uuwgs93IezB7mf7R60tC8ZbJideoDNKjHn2O9KIlx6rkGTTEk1xUCK2E1Y2Yg==} engines: {node: '>=10.13.0'} @@ -9066,6 +9452,11 @@ packages: engines: {node: '>=12'} hasBin: true + esbuild@0.25.0: + resolution: {integrity: sha512-BXq5mqc8ltbaN34cDqWuYKyNhX8D/Z0J1xdtdQ8UcIIIyJyz+ZMKUt58tF3SrZ85jcfN/PZYhjR5uDQAYNVbuw==} + engines: {node: '>=18'} + hasBin: true + esbuild@0.25.1: resolution: {integrity: sha512-BGO5LtrGC7vxnqucAe/rmvKdJllfGaYWdyABvyMoXQlfYMb2bbRuReWR5tEGE//4LcNJj9XrkovTqNYRFZHAMQ==} engines: {node: '>=18'} @@ -9337,6 +9728,9 @@ packages: extend@3.0.2: resolution: {integrity: sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==} + fast-deep-equal@2.0.1: + resolution: {integrity: sha512-bCK/2Z4zLidyB4ReuIsvALH6w31YfAQDmXMqMx6FyfHqvBxtjC0eRumeSu4Bs3XtXwpyIywtSTrVT99BxY1f9w==} + fast-deep-equal@3.1.3: resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} @@ -9583,6 +9977,11 @@ packages: engines: {node: '>=16 || 14 >=14.17'} hasBin: true + glob@10.3.4: + resolution: {integrity: sha512-6LFElP3A+i/Q8XQKEvZjkEWEOTgAIALR9AO2rwT8bgPhDd1anmqDJDZ6lLddI4ehxxxR1S5RIqKe1uapMQfYaQ==} + engines: {node: '>=16 || 14 >=14.17'} + hasBin: true + glob@10.4.5: resolution: {integrity: sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==} hasBin: true @@ -9767,6 +10166,10 @@ packages: html-escaper@2.0.2: resolution: {integrity: sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==} + html-to-text@9.0.5: + resolution: {integrity: sha512-qY60FjREgVZL03vJU6IfMV4GDjGBIoOyvuFdpBDIX9yTlDw0TjxVBQp+P8NvpdIXNJvfWBTNul7fsAQJq2FNpg==} + engines: {node: '>=14'} + html-void-elements@3.0.0: resolution: {integrity: sha512-bEqo66MRXsUGxWHV5IP0PUiAWwoEjba4VCzg0LjFJBpchPaTfyfCKTG6bc5F8ucKec3q5y6qOdGyYTSBEvhCrg==} @@ -9776,6 +10179,9 @@ packages: htmlfy@0.6.7: resolution: {integrity: sha512-r8hRd+oIM10lufovN+zr3VKPTYEIvIwqXGucidh2XQufmiw6sbUXFUFjWlfjo3AnefIDTyzykVzQ8IUVuT1peQ==} + htmlparser2@8.0.2: + resolution: {integrity: sha512-GYdjWKDkbRLkZ5geuHs5NY1puJ+PXwP7+fHPRz06Eirsb9ugf6d8kkXav6ADhcODhFFPMIXyxkxSuMf3D6NCFA==} + http-proxy-agent@5.0.0: resolution: {integrity: sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==} engines: {node: '>= 6'} @@ -10278,6 +10684,9 @@ packages: layout-base@1.0.2: resolution: {integrity: sha512-8h2oVEZNktL4BH2JCOI90iD1yXwL6iNW7KcCKT2QZgQJR2vbqDsldCTPRU9NifTCqHZci57XvQQ15YTu+sTYPg==} + leac@0.6.0: + resolution: {integrity: sha512-y+SqErxb8h7nE/fiEX07jsbuhrpO9lL8eca7/Y1nuWV2moNlXhyd59iDGcRf6moVyDMbmTNzL40SUyrFU/yDpg==} + levn@0.4.1: resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} engines: {node: '>= 0.8.0'} @@ -10392,6 +10801,11 @@ packages: markdown-table@3.0.4: resolution: {integrity: sha512-wiYz4+JrLyb/DqW2hkFJxP7Vd7JuTDm77fvbM8VfEQdmSMqcImWeeRbHwZjBjIFki/VaMK2BhFi7oUUZeM5bqw==} + marked@7.0.4: + resolution: {integrity: sha512-t8eP0dXRJMtMvBojtkcsA7n48BkauktUKzfkPSCq85ZMTJ0v76Rke4DYz01omYpPTUh4p/f7HePgRo3ebG8+QQ==} + engines: {node: '>= 16'} + hasBin: true + match-sorter@6.3.4: resolution: {integrity: sha512-jfZW7cWS5y/1xswZo8VBOdudUiSd9nifYRWphc9M5D/ee4w4AoXLgBEdRbgVaxbMuagBPeUC5y2Hi8DO6o9aDg==} @@ -10399,6 +10813,11 @@ packages: resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} engines: {node: '>= 0.4'} + md-to-react-email@5.0.5: + resolution: {integrity: sha512-OvAXqwq57uOk+WZqFFNCMZz8yDp8BD3WazW1wAKHUrPbbdr89K9DWS6JXY09vd9xNdPNeurI8DU/X4flcfaD8A==} + peerDependencies: + react: ^18.0 || ^19.0 + mdast-util-definitions@5.1.2: resolution: {integrity: sha512-8SVPMuHqlPME/z3gqVwWY4zVXn8lqKv/pAhC57FuJ40ImXyBpmO5ukh98zB2v7Blql2FiHjHv9LVztSIqjY+MA==} @@ -11096,6 +11515,10 @@ packages: resolution: {integrity: sha512-zAKMgGXUim0Jyd6CXK9lraBnD3H5yPGBPPOkC23a2BG6hsm4Zu6OQSjQuEtV0BHDf4aKHcUFvJiGRrFuW3MG8g==} engines: {node: '>=10'} + ora@5.4.1: + resolution: {integrity: sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==} + engines: {node: '>=10'} + orderedmap@2.1.1: resolution: {integrity: sha512-TvAWxi0nDe1j/rtMcWcIj94+Ffe6n7zhow33h40SKxmsmozs6dz/e+EajymfoFcHd7sxNn8yHM8839uixMOV6g==} @@ -11165,6 +11588,9 @@ packages: parse5@7.2.1: resolution: {integrity: sha512-BuBYQYlv1ckiPdQi/ohiivi9Sagc9JG+Ozs0r7b/0iK3sKmrb0b9FdWdBbOdx6hBCM/F9Ir82ofnBhtZOjCRPQ==} + parseley@0.12.1: + resolution: {integrity: sha512-e6qHKe3a9HWr0oMRVDTRhKce+bRO8VGQR3NyVwcjwrbhMmFCX9KszEV35+rn4AdilFAq9VPxP/Fe1wC9Qjd2lw==} + partykit@0.0.84: resolution: {integrity: sha512-qY9WfnEsOPVIYMmPuFye4H0V9JqKt3/Ylu2IBlJNEGTI4OQ9MJp/D24mznE5/KorfaL35MQSGmSuYbrOHa4Jwg==} hasBin: true @@ -11226,6 +11652,9 @@ packages: resolution: {integrity: sha512-rJmuBDFpD7cqC8WIkQUEClyB4UAH05K4AsyewToMTp2gSy3Rrx8c1ydAVqlJlGv3yZSOrhEERQU/4ScQQFlLHA==} engines: {node: '>=18'} + peberminta@0.9.0: + resolution: {integrity: sha512-XIxfHpEuSJbITd1H3EeQwpcZbTLHc+VVr8ANI9t5sit565tsI4/xK3KWTUFE2e6QiangUkh3B0jihzmGnNrRsQ==} + periscopic@3.1.0: resolution: {integrity: sha512-vKiQ8RRtkl9P+r/+oefh25C3fhybptkHKCZSPlcXiJux2tJF55GnEj3BVn4A5gKfq9NWWXXrxkHBwVPUfH0opw==} @@ -11440,6 +11869,10 @@ packages: printable-characters@1.0.42: resolution: {integrity: sha512-dKp+C4iXWK4vVYZmYSd0KBH5F/h1HoZRsbJ82AVKRO3PEo8L4lBS/vLwhVtpwwuYcoIsVY+1JYKR268yn480uQ==} + prismjs@1.30.0: + resolution: {integrity: sha512-DEvV2ZF2r2/63V+tK8hQvrR2ZGn10srHbXviTlcv7Kpzw8jWiNTqbVgjO3IY8RxrrOUF8VPMQQFysYYYv0YZxw==} + engines: {node: '>=6'} + proc-log@3.0.0: resolution: {integrity: sha512-++Vn7NS4Xf9NacaU9Xq3URUuqZETPsf8L4j5/ckhaRYsfPeRyzGw+iDjFhV/Jr3uNmTvvddEJFWh5R1gRgUH8A==} engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} @@ -11614,12 +12047,22 @@ packages: peerDependencies: react: ^18.3.1 + react-dom@19.1.0: + resolution: {integrity: sha512-Xs1hdnE+DyKgeHJeJznQmYMIBG3TKIHJJT95Q58nHLSrElKlGQqDTR2HQ9fx5CN/Gk6Vh/kupBTDLU11/nDk/g==} + peerDependencies: + react: ^19.1.0 + react-element-to-jsx-string@15.0.0: resolution: {integrity: sha512-UDg4lXB6BzlobN60P8fHWVPX3Kyw8ORrTeBtClmIlGdkOOE+GYQSFvmEU5iLLpwp/6v42DINwNcwOhOLfQ//FQ==} peerDependencies: react: ^0.14.8 || ^15.0.1 || ^16.0.0 || ^17.0.1 || ^18.0.0 react-dom: ^0.14.8 || ^15.0.1 || ^16.0.0 || ^17.0.1 || ^18.0.0 + react-email@4.0.7: + resolution: {integrity: sha512-XCXlfZLKv9gHd/ZwUEhCpRGc/FJLZGYczeuG1kVR/be2PlkwEB4gjX9ARBbRFv86ncbtpOu/wI6jD6kadRyAKw==} + engines: {node: '>=18.0.0'} + hasBin: true + react-github-btn@1.4.0: resolution: {integrity: sha512-lV4FYClAfjWnBfv0iNlJUGhamDgIq6TayD0kPZED6VzHWdpcHmPfsYOZ/CFwLfPv4Zp+F4m8QKTj0oy2HjiGXg==} peerDependencies: @@ -11657,6 +12100,9 @@ packages: react: ^0.14 || ^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 react-dom: ^0.14 || ^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + react-promise-suspense@0.3.4: + resolution: {integrity: sha512-I42jl7L3Ze6kZaq+7zXWSunBa3b1on5yfvUW6Eo/3fFOj6dZ5Bqmcd264nJbTK/gn1HjjILAjSwnZbV4RpSaNQ==} + react-refresh@0.14.2: resolution: {integrity: sha512-jCvmsr+1IUSMUyzOkRcvnVbX3ZYC6g9TDrDbFuFmRDq7PD4yaGbLKNQL6k2jnArV8hjYxh7hVhAZB6s9HDGpZA==} engines: {node: '>=0.10.0'} @@ -11720,6 +12166,10 @@ packages: resolution: {integrity: sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==} engines: {node: '>=0.10.0'} + react@19.1.0: + resolution: {integrity: sha512-FS+XFBNvn3GTAWq26joslQgWNoFu08F4kl0J4CgdNKADkdSGXQyTCnKteIAJy96Br6YbpEU1LSzV5dYtjMkMDg==} + engines: {node: '>=0.10.0'} + read-cache@1.0.0: resolution: {integrity: sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==} @@ -11734,6 +12184,10 @@ packages: resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} engines: {node: '>=8.10.0'} + readdirp@4.1.2: + resolution: {integrity: sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==} + engines: {node: '>= 14.18.0'} + reading-time@1.5.0: resolution: {integrity: sha512-onYyVhBNr4CmAxFsKS7bz+uTLRakypIe4R+5A824vBSkQy/hB3fZepoVEf8OVAxzLvK+H/jm9TzpI3ETSm64Kg==} @@ -12006,12 +12460,15 @@ packages: scheduler@0.25.0-rc-603e6108-20241029: resolution: {integrity: sha512-pFwF6H1XrSdYYNLfOcGlM28/j8CGLu8IvdrxqhjWULe2bPcKiKW4CV+OWqR/9fT52mywx65l7ysNkjLKBda7eA==} + scheduler@0.26.0: + resolution: {integrity: sha512-NlHwttCI/l5gCPR3D1nNXtWABUmBwvZpEQiD4IXSbIDq8BzLIK/7Ir5gTFSGZDUu37K5cMNp0hFtzO38sC7gWA==} + schema-utils@3.3.0: resolution: {integrity: sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==} engines: {node: '>= 10.13.0'} - schema-utils@4.3.0: - resolution: {integrity: sha512-Gf9qqc58SpCA/xdziiHz35F4GNIWYWZrEshUc/G/r5BnLph6xpKuLeoJoQuj5WfBIx/eQLf+hmVPYHaxJu7V2g==} + schema-utils@4.3.1: + resolution: {integrity: sha512-jjlZ7UknkyQxGnHF1w8wDgWfdtnW0hBX7tmDp04zBwDBZ/6tPJI1+RWfBHGMA4+0nAjGptp+eDpIYP6mldJbqg==} engines: {node: '>= 10.13.0'} scroll-into-view-if-needed@3.1.0: @@ -12021,6 +12478,9 @@ packages: resolution: {integrity: sha512-vfD3pmTzGpufjScBh50YHKzEu2lxBWhVEHsNGoEXmCmn2hKGfeNLYMzCJpe8cD7gqX7TJluOVpBkAequ6dgMmA==} engines: {node: '>=4'} + selderee@0.11.0: + resolution: {integrity: sha512-5TF+l7p4+OsnP8BCCvSyZiSPc4x4//p5uPwK8TCnVPJYRmU2aYKMpOXvw8zM5a5JvuuCGN1jmsMwuU2W02ukfA==} + semver@6.3.1: resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} hasBin: true @@ -12162,6 +12622,17 @@ packages: slate@0.110.2: resolution: {integrity: sha512-4xGULnyMCiEQ0Ml7JAC1A6HVE6MNpPJU7Eq4cXh1LxlrR0dFXC3XC+rNfQtUJ7chHoPkws57x7DDiWiZAt+PBA==} + socket.io-adapter@2.5.5: + resolution: {integrity: sha512-eLDQas5dzPgOWCk9GuuJC2lBqItuhKI4uxGgo9aIV7MYbk2h9Q6uULEh8WBzThoI7l+qU9Ast9fVUmkqPP9wYg==} + + socket.io-parser@4.2.4: + resolution: {integrity: sha512-/GbIKmo8ioc+NIWIhwdecY0ge+qVBSMdgxGygevmdHj24bsfgtCmcUUcQ5ZzcylGFHsN3k4HB4Cgkl96KVnuew==} + engines: {node: '>=10.0.0'} + + socket.io@4.8.1: + resolution: {integrity: sha512-oZ7iUCxph8WYRHHcjBEc9unw3adt5CmSNlppj/5Q4k2RIrhl8Z5yY2Xr4j9zj0+wzVZ0bxmYoGSzKJnRl6A4yg==} + engines: {node: '>=10.2.0'} + sort-keys@5.1.0: resolution: {integrity: sha512-aSbHV0DaBcr7u0PVHXzM6NbZNAtrr9sF6+Qfs9UUVG7Ll3jQ6hHi8F/xqIIcn2rvIVbr0v/2zyjSdwSV47AgLQ==} engines: {node: '>=12'} @@ -12616,6 +13087,9 @@ packages: undici-types@6.20.0: resolution: {integrity: sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==} + undici-types@6.21.0: + resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==} + undici@5.29.0: resolution: {integrity: sha512-raqeBD6NQK4SkWhQzeYKd1KmIG6dllBOTt55Rmkt4HtI9mwdWtJljnrXjAFUBLTSN67HWrOIZ3EPF4kjUw80Bg==} engines: {node: '>=14.0'} @@ -13063,6 +13537,18 @@ packages: utf-8-validate: optional: true + ws@8.17.1: + resolution: {integrity: sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==} + engines: {node: '>=10.0.0'} + peerDependencies: + bufferutil: ^4.0.1 + utf-8-validate: '>=5.0.2' + peerDependenciesMeta: + bufferutil: + optional: true + utf-8-validate: + optional: true + ws@8.18.1: resolution: {integrity: sha512-RKW2aJZMXeMxVpnZ6bck+RswznaxmzdULiBr6KY7XkTnW8uvt0iT9H5DkHUChXrc+uurzwa0rVI16n/Xzjdz1w==} engines: {node: '>=10.0.0'} @@ -13874,6 +14360,10 @@ snapshots: '@babel/template': 7.27.0 '@babel/types': 7.27.0 + '@babel/parser@7.24.5': + dependencies: + '@babel/types': 7.27.0 + '@babel/parser@7.27.0': dependencies: '@babel/types': 7.27.0 @@ -14531,7 +15021,7 @@ snapshots: '@babel/parser': 7.27.0 '@babel/types': 7.27.0 - '@babel/traverse@7.27.0': + '@babel/traverse@7.25.6': dependencies: '@babel/code-frame': 7.26.2 '@babel/generator': 7.27.0 @@ -14543,7 +15033,19 @@ snapshots: transitivePeerDependencies: - supports-color - '@babel/types@7.27.0': + '@babel/traverse@7.27.0': + dependencies: + '@babel/code-frame': 7.26.2 + '@babel/generator': 7.27.0 + '@babel/parser': 7.27.0 + '@babel/template': 7.27.0 + '@babel/types': 7.27.0 + debug: 4.4.0 + globals: 11.12.0 + transitivePeerDependencies: + - supports-color + + '@babel/types@7.27.0': dependencies: '@babel/helper-string-parser': 7.25.9 '@babel/helper-validator-identifier': 7.25.9 @@ -14716,6 +15218,9 @@ snapshots: '@esbuild/aix-ppc64@0.21.5': optional: true + '@esbuild/aix-ppc64@0.25.0': + optional: true + '@esbuild/aix-ppc64@0.25.1': optional: true @@ -14725,6 +15230,9 @@ snapshots: '@esbuild/android-arm64@0.21.5': optional: true + '@esbuild/android-arm64@0.25.0': + optional: true + '@esbuild/android-arm64@0.25.1': optional: true @@ -14734,6 +15242,9 @@ snapshots: '@esbuild/android-arm@0.21.5': optional: true + '@esbuild/android-arm@0.25.0': + optional: true + '@esbuild/android-arm@0.25.1': optional: true @@ -14743,6 +15254,9 @@ snapshots: '@esbuild/android-x64@0.21.5': optional: true + '@esbuild/android-x64@0.25.0': + optional: true + '@esbuild/android-x64@0.25.1': optional: true @@ -14752,6 +15266,9 @@ snapshots: '@esbuild/darwin-arm64@0.21.5': optional: true + '@esbuild/darwin-arm64@0.25.0': + optional: true + '@esbuild/darwin-arm64@0.25.1': optional: true @@ -14761,6 +15278,9 @@ snapshots: '@esbuild/darwin-x64@0.21.5': optional: true + '@esbuild/darwin-x64@0.25.0': + optional: true + '@esbuild/darwin-x64@0.25.1': optional: true @@ -14770,6 +15290,9 @@ snapshots: '@esbuild/freebsd-arm64@0.21.5': optional: true + '@esbuild/freebsd-arm64@0.25.0': + optional: true + '@esbuild/freebsd-arm64@0.25.1': optional: true @@ -14779,6 +15302,9 @@ snapshots: '@esbuild/freebsd-x64@0.21.5': optional: true + '@esbuild/freebsd-x64@0.25.0': + optional: true + '@esbuild/freebsd-x64@0.25.1': optional: true @@ -14788,6 +15314,9 @@ snapshots: '@esbuild/linux-arm64@0.21.5': optional: true + '@esbuild/linux-arm64@0.25.0': + optional: true + '@esbuild/linux-arm64@0.25.1': optional: true @@ -14797,6 +15326,9 @@ snapshots: '@esbuild/linux-arm@0.21.5': optional: true + '@esbuild/linux-arm@0.25.0': + optional: true + '@esbuild/linux-arm@0.25.1': optional: true @@ -14806,6 +15338,9 @@ snapshots: '@esbuild/linux-ia32@0.21.5': optional: true + '@esbuild/linux-ia32@0.25.0': + optional: true + '@esbuild/linux-ia32@0.25.1': optional: true @@ -14815,6 +15350,9 @@ snapshots: '@esbuild/linux-loong64@0.21.5': optional: true + '@esbuild/linux-loong64@0.25.0': + optional: true + '@esbuild/linux-loong64@0.25.1': optional: true @@ -14824,6 +15362,9 @@ snapshots: '@esbuild/linux-mips64el@0.21.5': optional: true + '@esbuild/linux-mips64el@0.25.0': + optional: true + '@esbuild/linux-mips64el@0.25.1': optional: true @@ -14833,6 +15374,9 @@ snapshots: '@esbuild/linux-ppc64@0.21.5': optional: true + '@esbuild/linux-ppc64@0.25.0': + optional: true + '@esbuild/linux-ppc64@0.25.1': optional: true @@ -14842,6 +15386,9 @@ snapshots: '@esbuild/linux-riscv64@0.21.5': optional: true + '@esbuild/linux-riscv64@0.25.0': + optional: true + '@esbuild/linux-riscv64@0.25.1': optional: true @@ -14851,6 +15398,9 @@ snapshots: '@esbuild/linux-s390x@0.21.5': optional: true + '@esbuild/linux-s390x@0.25.0': + optional: true + '@esbuild/linux-s390x@0.25.1': optional: true @@ -14860,9 +15410,15 @@ snapshots: '@esbuild/linux-x64@0.21.5': optional: true + '@esbuild/linux-x64@0.25.0': + optional: true + '@esbuild/linux-x64@0.25.1': optional: true + '@esbuild/netbsd-arm64@0.25.0': + optional: true + '@esbuild/netbsd-arm64@0.25.1': optional: true @@ -14872,9 +15428,15 @@ snapshots: '@esbuild/netbsd-x64@0.21.5': optional: true + '@esbuild/netbsd-x64@0.25.0': + optional: true + '@esbuild/netbsd-x64@0.25.1': optional: true + '@esbuild/openbsd-arm64@0.25.0': + optional: true + '@esbuild/openbsd-arm64@0.25.1': optional: true @@ -14884,6 +15446,9 @@ snapshots: '@esbuild/openbsd-x64@0.21.5': optional: true + '@esbuild/openbsd-x64@0.25.0': + optional: true + '@esbuild/openbsd-x64@0.25.1': optional: true @@ -14893,6 +15458,9 @@ snapshots: '@esbuild/sunos-x64@0.21.5': optional: true + '@esbuild/sunos-x64@0.25.0': + optional: true + '@esbuild/sunos-x64@0.25.1': optional: true @@ -14902,6 +15470,9 @@ snapshots: '@esbuild/win32-arm64@0.21.5': optional: true + '@esbuild/win32-arm64@0.25.0': + optional: true + '@esbuild/win32-arm64@0.25.1': optional: true @@ -14911,6 +15482,9 @@ snapshots: '@esbuild/win32-ia32@0.21.5': optional: true + '@esbuild/win32-ia32@0.25.0': + optional: true + '@esbuild/win32-ia32@0.25.1': optional: true @@ -14920,6 +15494,9 @@ snapshots: '@esbuild/win32-x64@0.21.5': optional: true + '@esbuild/win32-x64@0.25.0': + optional: true + '@esbuild/win32-x64@0.25.1': optional: true @@ -15960,27 +16537,27 @@ snapshots: '@polar-sh/adapter-utils@0.1.15(zod@3.24.2)': dependencies: - '@polar-sh/sdk': 0.32.10(zod@3.24.2) + '@polar-sh/sdk': 0.32.11(zod@3.24.2) transitivePeerDependencies: - '@modelcontextprotocol/sdk' - zod - '@polar-sh/better-auth@0.1.0(@polar-sh/sdk@0.32.10(zod@3.24.2))(better-auth@1.2.7)': + '@polar-sh/better-auth@0.1.0(@polar-sh/sdk@0.32.11(zod@3.24.2))(better-auth@1.2.7)': dependencies: - '@polar-sh/sdk': 0.32.10(zod@3.24.2) + '@polar-sh/sdk': 0.32.11(zod@3.24.2) better-auth: 1.2.7 zod: 3.24.2 '@polar-sh/nextjs@0.3.23(next@15.2.4(@babel/core@7.26.10)(@opentelemetry/api@1.9.0)(@playwright/test@1.51.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(zod@3.24.2)': dependencies: '@polar-sh/adapter-utils': 0.1.15(zod@3.24.2) - '@polar-sh/sdk': 0.32.10(zod@3.24.2) + '@polar-sh/sdk': 0.32.11(zod@3.24.2) next: 15.2.4(@babel/core@7.26.10)(@opentelemetry/api@1.9.0)(@playwright/test@1.51.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) transitivePeerDependencies: - '@modelcontextprotocol/sdk' - zod - '@polar-sh/sdk@0.32.10(zod@3.24.2)': + '@polar-sh/sdk@0.32.11(zod@3.24.2)': dependencies: standardwebhooks: 1.0.0 zod: 3.24.2 @@ -16389,6 +16966,230 @@ snapshots: '@radix-ui/rect@1.1.0': {} + '@react-email/body@0.0.11(react@18.3.1)': + dependencies: + react: 18.3.1 + + '@react-email/body@0.0.11(react@19.1.0)': + dependencies: + react: 19.1.0 + + '@react-email/button@0.0.19(react@18.3.1)': + dependencies: + react: 18.3.1 + + '@react-email/button@0.0.19(react@19.1.0)': + dependencies: + react: 19.1.0 + + '@react-email/code-block@0.0.12(react@18.3.1)': + dependencies: + prismjs: 1.30.0 + react: 18.3.1 + + '@react-email/code-block@0.0.12(react@19.1.0)': + dependencies: + prismjs: 1.30.0 + react: 19.1.0 + + '@react-email/code-inline@0.0.5(react@18.3.1)': + dependencies: + react: 18.3.1 + + '@react-email/code-inline@0.0.5(react@19.1.0)': + dependencies: + react: 19.1.0 + + '@react-email/column@0.0.13(react@18.3.1)': + dependencies: + react: 18.3.1 + + '@react-email/column@0.0.13(react@19.1.0)': + dependencies: + react: 19.1.0 + + '@react-email/components@0.0.36(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + dependencies: + '@react-email/body': 0.0.11(react@18.3.1) + '@react-email/button': 0.0.19(react@18.3.1) + '@react-email/code-block': 0.0.12(react@18.3.1) + '@react-email/code-inline': 0.0.5(react@18.3.1) + '@react-email/column': 0.0.13(react@18.3.1) + '@react-email/container': 0.0.15(react@18.3.1) + '@react-email/font': 0.0.9(react@18.3.1) + '@react-email/head': 0.0.12(react@18.3.1) + '@react-email/heading': 0.0.15(react@18.3.1) + '@react-email/hr': 0.0.11(react@18.3.1) + '@react-email/html': 0.0.11(react@18.3.1) + '@react-email/img': 0.0.11(react@18.3.1) + '@react-email/link': 0.0.12(react@18.3.1) + '@react-email/markdown': 0.0.14(react@18.3.1) + '@react-email/preview': 0.0.12(react@18.3.1) + '@react-email/render': 1.0.6(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@react-email/row': 0.0.12(react@18.3.1) + '@react-email/section': 0.0.16(react@18.3.1) + '@react-email/tailwind': 1.0.4(react@18.3.1) + '@react-email/text': 0.1.1(react@18.3.1) + react: 18.3.1 + transitivePeerDependencies: + - react-dom + + '@react-email/components@0.0.36(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + dependencies: + '@react-email/body': 0.0.11(react@19.1.0) + '@react-email/button': 0.0.19(react@19.1.0) + '@react-email/code-block': 0.0.12(react@19.1.0) + '@react-email/code-inline': 0.0.5(react@19.1.0) + '@react-email/column': 0.0.13(react@19.1.0) + '@react-email/container': 0.0.15(react@19.1.0) + '@react-email/font': 0.0.9(react@19.1.0) + '@react-email/head': 0.0.12(react@19.1.0) + '@react-email/heading': 0.0.15(react@19.1.0) + '@react-email/hr': 0.0.11(react@19.1.0) + '@react-email/html': 0.0.11(react@19.1.0) + '@react-email/img': 0.0.11(react@19.1.0) + '@react-email/link': 0.0.12(react@19.1.0) + '@react-email/markdown': 0.0.14(react@19.1.0) + '@react-email/preview': 0.0.12(react@19.1.0) + '@react-email/render': 1.0.6(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@react-email/row': 0.0.12(react@19.1.0) + '@react-email/section': 0.0.16(react@19.1.0) + '@react-email/tailwind': 1.0.4(react@19.1.0) + '@react-email/text': 0.1.1(react@19.1.0) + react: 19.1.0 + transitivePeerDependencies: + - react-dom + + '@react-email/container@0.0.15(react@18.3.1)': + dependencies: + react: 18.3.1 + + '@react-email/container@0.0.15(react@19.1.0)': + dependencies: + react: 19.1.0 + + '@react-email/font@0.0.9(react@18.3.1)': + dependencies: + react: 18.3.1 + + '@react-email/font@0.0.9(react@19.1.0)': + dependencies: + react: 19.1.0 + + '@react-email/head@0.0.12(react@18.3.1)': + dependencies: + react: 18.3.1 + + '@react-email/head@0.0.12(react@19.1.0)': + dependencies: + react: 19.1.0 + + '@react-email/heading@0.0.15(react@18.3.1)': + dependencies: + react: 18.3.1 + + '@react-email/heading@0.0.15(react@19.1.0)': + dependencies: + react: 19.1.0 + + '@react-email/hr@0.0.11(react@18.3.1)': + dependencies: + react: 18.3.1 + + '@react-email/hr@0.0.11(react@19.1.0)': + dependencies: + react: 19.1.0 + + '@react-email/html@0.0.11(react@18.3.1)': + dependencies: + react: 18.3.1 + + '@react-email/html@0.0.11(react@19.1.0)': + dependencies: + react: 19.1.0 + + '@react-email/img@0.0.11(react@18.3.1)': + dependencies: + react: 18.3.1 + + '@react-email/img@0.0.11(react@19.1.0)': + dependencies: + react: 19.1.0 + + '@react-email/link@0.0.12(react@18.3.1)': + dependencies: + react: 18.3.1 + + '@react-email/link@0.0.12(react@19.1.0)': + dependencies: + react: 19.1.0 + + '@react-email/markdown@0.0.14(react@18.3.1)': + dependencies: + md-to-react-email: 5.0.5(react@18.3.1) + react: 18.3.1 + + '@react-email/markdown@0.0.14(react@19.1.0)': + dependencies: + md-to-react-email: 5.0.5(react@19.1.0) + react: 19.1.0 + + '@react-email/preview@0.0.12(react@18.3.1)': + dependencies: + react: 18.3.1 + + '@react-email/preview@0.0.12(react@19.1.0)': + dependencies: + react: 19.1.0 + + '@react-email/render@1.0.6(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + dependencies: + html-to-text: 9.0.5 + prettier: 3.5.3 + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + react-promise-suspense: 0.3.4 + + '@react-email/render@1.0.6(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + dependencies: + html-to-text: 9.0.5 + prettier: 3.5.3 + react: 19.1.0 + react-dom: 19.1.0(react@19.1.0) + react-promise-suspense: 0.3.4 + + '@react-email/row@0.0.12(react@18.3.1)': + dependencies: + react: 18.3.1 + + '@react-email/row@0.0.12(react@19.1.0)': + dependencies: + react: 19.1.0 + + '@react-email/section@0.0.16(react@18.3.1)': + dependencies: + react: 18.3.1 + + '@react-email/section@0.0.16(react@19.1.0)': + dependencies: + react: 19.1.0 + + '@react-email/tailwind@1.0.4(react@18.3.1)': + dependencies: + react: 18.3.1 + + '@react-email/tailwind@1.0.4(react@19.1.0)': + dependencies: + react: 19.1.0 + + '@react-email/text@0.1.1(react@18.3.1)': + dependencies: + react: 18.3.1 + + '@react-email/text@0.1.1(react@19.1.0)': + dependencies: + react: 19.1.0 + '@react-pdf/fns@3.1.2': {} '@react-pdf/font@4.0.2': @@ -16585,6 +17386,11 @@ snapshots: '@rushstack/eslint-patch@1.11.0': {} + '@selderee/plugin-htmlparser2@0.11.0': + dependencies: + domhandler: 5.0.3 + selderee: 0.11.0 + '@sentry-internal/browser-utils@9.4.0': dependencies: '@sentry/core': 9.4.0 @@ -17158,6 +17964,8 @@ snapshots: '@smithy/types': 4.2.0 tslib: 2.8.1 + '@socket.io/component-emitter@3.1.2': {} + '@stablelib/base64@1.0.1': {} '@swc/counter@0.1.3': {} @@ -17379,6 +18187,10 @@ snapshots: '@types/cookie@0.6.0': {} + '@types/cors@2.8.17': + dependencies: + '@types/node': 20.17.30 + '@types/d3-scale-chromatic@3.1.0': {} '@types/d3-scale@4.0.9': @@ -17393,7 +18205,7 @@ snapshots: '@types/emoji-mart@3.0.14': dependencies: - '@types/react': 19.0.12 + '@types/react': 19.1.2 '@types/eslint-scope@3.7.7': dependencies: @@ -17512,6 +18324,11 @@ snapshots: dependencies: undici-types: 6.20.0 + '@types/node@22.14.1': + dependencies: + undici-types: 6.21.0 + optional: true + '@types/nodemailer@6.4.17': dependencies: '@types/node': 20.17.30 @@ -17538,6 +18355,10 @@ snapshots: dependencies: '@types/react': 18.3.20 + '@types/react-dom@19.1.2(@types/react@19.1.2)': + dependencies: + '@types/react': 19.1.2 + '@types/react-transition-group@4.4.12(@types/react@18.3.20)': dependencies: '@types/react': 18.3.20 @@ -17547,7 +18368,7 @@ snapshots: '@types/prop-types': 15.7.14 csstype: 3.1.3 - '@types/react@19.0.12': + '@types/react@19.1.2': dependencies: csstype: 3.1.3 @@ -17869,14 +18690,14 @@ snapshots: transitivePeerDependencies: - supports-color - '@vitejs/plugin-react@4.3.4(vite@5.4.15(@types/node@22.13.13)(terser@5.39.0))': + '@vitejs/plugin-react@4.3.4(vite@5.4.15(@types/node@22.14.1)(terser@5.39.0))': dependencies: '@babel/core': 7.26.10 '@babel/plugin-transform-react-jsx-self': 7.25.9(@babel/core@7.26.10) '@babel/plugin-transform-react-jsx-source': 7.25.9(@babel/core@7.26.10) '@types/babel__core': 7.20.5 react-refresh: 0.14.2 - vite: 5.4.15(@types/node@22.13.13)(terser@5.39.0) + vite: 5.4.15(@types/node@22.14.1)(terser@5.39.0) transitivePeerDependencies: - supports-color @@ -17895,13 +18716,13 @@ snapshots: optionalDependencies: vite: 5.4.15(@types/node@20.17.28)(terser@5.39.0) - '@vitest/mocker@2.1.9(vite@5.4.15(@types/node@22.13.13)(terser@5.39.0))': + '@vitest/mocker@2.1.9(vite@5.4.15(@types/node@22.14.1)(terser@5.39.0))': dependencies: '@vitest/spy': 2.1.9 estree-walker: 3.0.3 magic-string: 0.30.17 optionalDependencies: - vite: 5.4.15(@types/node@22.13.13)(terser@5.39.0) + vite: 5.4.15(@types/node@22.14.1)(terser@5.39.0) '@vitest/pretty-format@2.1.9': dependencies: @@ -17931,7 +18752,7 @@ snapshots: sirv: 3.0.1 tinyglobby: 0.2.12 tinyrainbow: 1.2.0 - vitest: 2.1.9(@types/node@22.13.13)(@vitest/ui@2.1.9)(jsdom@25.0.1(canvas@2.11.2(encoding@0.1.13)))(terser@5.39.0) + vitest: 2.1.9(@types/node@22.14.1)(@vitest/ui@2.1.9)(jsdom@25.0.1(canvas@2.11.2(encoding@0.1.13)))(terser@5.39.0) '@vitest/utils@2.1.9': dependencies: @@ -18382,6 +19203,8 @@ snapshots: base64-js@1.5.1: {} + base64id@2.0.0: {} + better-auth@1.2.7: dependencies: '@better-auth/utils': 0.2.4 @@ -18591,6 +19414,10 @@ snapshots: optionalDependencies: fsevents: 2.3.3 + chokidar@4.0.3: + dependencies: + readdirp: 4.1.2 + chownr@1.1.4: {} chownr@2.0.0: @@ -18698,6 +19525,8 @@ snapshots: comma-separated-tokens@2.0.3: {} + commander@11.1.0: {} + commander@2.20.3: {} commander@4.1.1: {} @@ -18759,6 +19588,11 @@ snapshots: core-util-is@1.0.3: {} + cors@2.8.5: + dependencies: + object-assign: 4.1.1 + vary: 1.1.2 + cose-base@1.0.3: dependencies: layout-base: 1.0.2 @@ -19032,6 +19866,8 @@ snapshots: debounce@1.2.1: {} + debounce@2.0.0: {} + debug@2.6.9: dependencies: ms: 2.0.0 @@ -19040,6 +19876,10 @@ snapshots: dependencies: ms: 2.1.3 + debug@4.3.7: + dependencies: + ms: 2.1.3 + debug@4.4.0: dependencies: ms: 2.1.3 @@ -19065,6 +19905,8 @@ snapshots: deep-is@0.1.4: {} + deepmerge@4.3.1: {} + defaults@1.0.4: dependencies: clone: 1.0.4 @@ -19151,12 +19993,30 @@ snapshots: '@babel/runtime': 7.27.0 csstype: 3.1.3 + dom-serializer@2.0.0: + dependencies: + domelementtype: 2.3.0 + domhandler: 5.0.3 + entities: 4.5.0 + + domelementtype@2.3.0: {} + domexception@4.0.0: dependencies: webidl-conversions: 7.0.0 + domhandler@5.0.3: + dependencies: + domelementtype: 2.3.0 + dompurify@3.1.6: {} + domutils@3.2.2: + dependencies: + dom-serializer: 2.0.0 + domelementtype: 2.3.0 + domhandler: 5.0.3 + dotenv-expand@11.0.7: dependencies: dotenv: 16.4.7 @@ -19202,6 +20062,24 @@ snapshots: dependencies: once: 1.4.0 + engine.io-parser@5.2.3: {} + + engine.io@6.6.4: + dependencies: + '@types/cors': 2.8.17 + '@types/node': 20.17.30 + accepts: 1.3.8 + base64id: 2.0.0 + cookie: 0.7.2 + cors: 2.8.5 + debug: 4.3.7 + engine.io-parser: 5.2.3 + ws: 8.17.1 + transitivePeerDependencies: + - bufferutil + - supports-color + - utf-8-validate + enhanced-resolve@5.18.1: dependencies: graceful-fs: 4.2.11 @@ -19369,6 +20247,34 @@ snapshots: '@esbuild/win32-ia32': 0.21.5 '@esbuild/win32-x64': 0.21.5 + esbuild@0.25.0: + optionalDependencies: + '@esbuild/aix-ppc64': 0.25.0 + '@esbuild/android-arm': 0.25.0 + '@esbuild/android-arm64': 0.25.0 + '@esbuild/android-x64': 0.25.0 + '@esbuild/darwin-arm64': 0.25.0 + '@esbuild/darwin-x64': 0.25.0 + '@esbuild/freebsd-arm64': 0.25.0 + '@esbuild/freebsd-x64': 0.25.0 + '@esbuild/linux-arm': 0.25.0 + '@esbuild/linux-arm64': 0.25.0 + '@esbuild/linux-ia32': 0.25.0 + '@esbuild/linux-loong64': 0.25.0 + '@esbuild/linux-mips64el': 0.25.0 + '@esbuild/linux-ppc64': 0.25.0 + '@esbuild/linux-riscv64': 0.25.0 + '@esbuild/linux-s390x': 0.25.0 + '@esbuild/linux-x64': 0.25.0 + '@esbuild/netbsd-arm64': 0.25.0 + '@esbuild/netbsd-x64': 0.25.0 + '@esbuild/openbsd-arm64': 0.25.0 + '@esbuild/openbsd-x64': 0.25.0 + '@esbuild/sunos-x64': 0.25.0 + '@esbuild/win32-arm64': 0.25.0 + '@esbuild/win32-ia32': 0.25.0 + '@esbuild/win32-x64': 0.25.0 + esbuild@0.25.1: optionalDependencies: '@esbuild/aix-ppc64': 0.25.1 @@ -19424,7 +20330,7 @@ snapshots: '@typescript-eslint/parser': 5.62.0(eslint@8.57.1)(typescript@5.8.2) eslint: 8.57.1 eslint-import-resolver-node: 0.3.9 - eslint-import-resolver-typescript: 3.10.0(eslint-plugin-import@2.31.0(@typescript-eslint/parser@5.62.0(eslint@8.57.1)(typescript@5.8.2))(eslint@8.57.1))(eslint@8.57.1) + eslint-import-resolver-typescript: 3.10.0(eslint-plugin-import@2.31.0)(eslint@8.57.1) eslint-plugin-import: 2.31.0(@typescript-eslint/parser@5.62.0(eslint@8.57.1)(typescript@5.8.2))(eslint-import-resolver-typescript@3.10.0)(eslint@8.57.1) eslint-plugin-jsx-a11y: 6.10.2(eslint@8.57.1) eslint-plugin-react: 7.37.4(eslint@8.57.1) @@ -19471,7 +20377,7 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-import-resolver-typescript@3.10.0(eslint-plugin-import@2.31.0(@typescript-eslint/parser@5.62.0(eslint@8.57.1)(typescript@5.8.2))(eslint@8.57.1))(eslint@8.57.1): + eslint-import-resolver-typescript@3.10.0(eslint-plugin-import@2.31.0)(eslint@8.57.1): dependencies: '@nolyfill/is-core-module': 1.0.39 debug: 4.4.0 @@ -19486,14 +20392,14 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-module-utils@2.12.0(@typescript-eslint/parser@5.62.0(eslint@8.57.1)(typescript@5.8.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.0(eslint-plugin-import@2.31.0(@typescript-eslint/parser@5.62.0(eslint@8.57.1)(typescript@5.8.2))(eslint@8.57.1))(eslint@8.57.1))(eslint@8.57.1): + eslint-module-utils@2.12.0(@typescript-eslint/parser@5.62.0(eslint@8.57.1)(typescript@5.8.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.0)(eslint@8.57.1): dependencies: debug: 3.2.7 optionalDependencies: '@typescript-eslint/parser': 5.62.0(eslint@8.57.1)(typescript@5.8.2) eslint: 8.57.1 eslint-import-resolver-node: 0.3.9 - eslint-import-resolver-typescript: 3.10.0(eslint-plugin-import@2.31.0(@typescript-eslint/parser@5.62.0(eslint@8.57.1)(typescript@5.8.2))(eslint@8.57.1))(eslint@8.57.1) + eslint-import-resolver-typescript: 3.10.0(eslint-plugin-import@2.31.0)(eslint@8.57.1) transitivePeerDependencies: - supports-color @@ -19516,7 +20422,7 @@ snapshots: doctrine: 2.1.0 eslint: 8.57.1 eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.12.0(@typescript-eslint/parser@5.62.0(eslint@8.57.1)(typescript@5.8.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.0(eslint-plugin-import@2.31.0(@typescript-eslint/parser@5.62.0(eslint@8.57.1)(typescript@5.8.2))(eslint@8.57.1))(eslint@8.57.1))(eslint@8.57.1) + eslint-module-utils: 2.12.0(@typescript-eslint/parser@5.62.0(eslint@8.57.1)(typescript@5.8.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.0)(eslint@8.57.1) hasown: 2.0.2 is-core-module: 2.16.1 is-glob: 4.0.3 @@ -19773,6 +20679,8 @@ snapshots: extend@3.0.2: {} + fast-deep-equal@2.0.1: {} + fast-deep-equal@3.1.3: {} fast-glob@3.3.3: @@ -20019,6 +20927,14 @@ snapshots: minipass: 7.1.2 path-scurry: 1.11.1 + glob@10.3.4: + dependencies: + foreground-child: 3.3.1 + jackspeak: 2.3.6 + minimatch: 9.0.5 + minipass: 7.1.2 + path-scurry: 1.11.1 + glob@10.4.5: dependencies: foreground-child: 3.3.1 @@ -20327,12 +21243,27 @@ snapshots: html-escaper@2.0.2: {} + html-to-text@9.0.5: + dependencies: + '@selderee/plugin-htmlparser2': 0.11.0 + deepmerge: 4.3.1 + dom-serializer: 2.0.0 + htmlparser2: 8.0.2 + selderee: 0.11.0 + html-void-elements@3.0.0: {} html-whitespace-sensitive-tag-names@3.0.1: {} htmlfy@0.6.7: {} + htmlparser2@8.0.2: + dependencies: + domelementtype: 2.3.0 + domhandler: 5.0.3 + domutils: 3.2.2 + entities: 4.5.0 + http-proxy-agent@5.0.0: dependencies: '@tootallnate/once': 2.0.0 @@ -20865,6 +21796,8 @@ snapshots: layout-base@1.0.2: {} + leac@0.6.0: {} + levn@0.4.1: dependencies: prelude-ls: 1.2.1 @@ -20973,6 +21906,8 @@ snapshots: markdown-table@3.0.4: {} + marked@7.0.4: {} + match-sorter@6.3.4: dependencies: '@babel/runtime': 7.27.0 @@ -20980,6 +21915,16 @@ snapshots: math-intrinsics@1.1.0: {} + md-to-react-email@5.0.5(react@18.3.1): + dependencies: + marked: 7.0.4 + react: 18.3.1 + + md-to-react-email@5.0.5(react@19.1.0): + dependencies: + marked: 7.0.4 + react: 19.1.0 + mdast-util-definitions@5.1.2: dependencies: '@types/mdast': 3.0.15 @@ -21947,6 +22892,33 @@ snapshots: - '@babel/core' - babel-plugin-macros + next@15.2.4(@babel/core@7.26.10)(@opentelemetry/api@1.9.0)(@playwright/test@1.51.1)(react-dom@19.1.0(react@19.1.0))(react@19.1.0): + dependencies: + '@next/env': 15.2.4 + '@swc/counter': 0.1.3 + '@swc/helpers': 0.5.15 + busboy: 1.6.0 + caniuse-lite: 1.0.30001707 + postcss: 8.4.31 + react: 19.1.0 + react-dom: 19.1.0(react@19.1.0) + styled-jsx: 5.1.6(@babel/core@7.26.10)(react@19.1.0) + optionalDependencies: + '@next/swc-darwin-arm64': 15.2.4 + '@next/swc-darwin-x64': 15.2.4 + '@next/swc-linux-arm64-gnu': 15.2.4 + '@next/swc-linux-arm64-musl': 15.2.4 + '@next/swc-linux-x64-gnu': 15.2.4 + '@next/swc-linux-x64-musl': 15.2.4 + '@next/swc-win32-arm64-msvc': 15.2.4 + '@next/swc-win32-x64-msvc': 15.2.4 + '@opentelemetry/api': 1.9.0 + '@playwright/test': 1.51.1 + sharp: 0.33.5 + transitivePeerDependencies: + - '@babel/core' + - babel-plugin-macros + nextra-theme-docs@2.13.4(next@15.2.4(@babel/core@7.26.10)(@opentelemetry/api@1.9.0)(@playwright/test@1.51.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(nextra@2.13.4(next@15.2.4(@babel/core@7.26.10)(@opentelemetry/api@1.9.0)(@playwright/test@1.51.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1): dependencies: '@headlessui/react': 1.7.19(react-dom@18.3.1(react@18.3.1))(react@18.3.1) @@ -22212,6 +23184,18 @@ snapshots: strip-ansi: 6.0.1 wcwidth: 1.0.1 + ora@5.4.1: + dependencies: + bl: 4.1.0 + chalk: 4.1.2 + cli-cursor: 3.1.0 + cli-spinners: 2.9.2 + is-interactive: 1.0.0 + is-unicode-supported: 0.1.0 + log-symbols: 4.1.0 + strip-ansi: 6.0.1 + wcwidth: 1.0.1 + orderedmap@2.1.1: {} own-keys@1.0.1: @@ -22291,6 +23275,11 @@ snapshots: dependencies: entities: 4.5.0 + parseley@0.12.1: + dependencies: + leac: 0.6.0 + peberminta: 0.9.0 + partykit@0.0.84: dependencies: '@cloudflare/workers-types': 4.20240129.0 @@ -22351,6 +23340,8 @@ snapshots: - encoding - supports-color + peberminta@0.9.0: {} + periscopic@3.1.0: dependencies: '@types/estree': 1.0.7 @@ -22498,6 +23489,8 @@ snapshots: printable-characters@1.0.42: {} + prismjs@1.30.0: {} + proc-log@3.0.0: {} process-nextick-args@2.0.1: {} @@ -22684,6 +23677,11 @@ snapshots: react: 18.3.1 scheduler: 0.23.2 + react-dom@19.1.0(react@19.1.0): + dependencies: + react: 19.1.0 + scheduler: 0.26.0 + react-element-to-jsx-string@15.0.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1): dependencies: '@base2/pretty-print-object': 1.0.1 @@ -22692,6 +23690,64 @@ snapshots: react-dom: 18.3.1(react@18.3.1) react-is: 18.1.0 + react-email@4.0.7(@babel/core@7.26.10)(@opentelemetry/api@1.9.0)(@playwright/test@1.51.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1): + dependencies: + '@babel/parser': 7.24.5 + '@babel/traverse': 7.25.6 + chalk: 4.1.2 + chokidar: 4.0.3 + commander: 11.1.0 + debounce: 2.0.0 + esbuild: 0.25.0 + glob: 10.3.4 + log-symbols: 4.1.0 + mime-types: 2.1.35 + next: 15.2.4(@babel/core@7.26.10)(@opentelemetry/api@1.9.0)(@playwright/test@1.51.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + normalize-path: 3.0.0 + ora: 5.4.1 + socket.io: 4.8.1 + transitivePeerDependencies: + - '@babel/core' + - '@opentelemetry/api' + - '@playwright/test' + - babel-plugin-macros + - babel-plugin-react-compiler + - bufferutil + - react + - react-dom + - sass + - supports-color + - utf-8-validate + + react-email@4.0.7(@babel/core@7.26.10)(@opentelemetry/api@1.9.0)(@playwright/test@1.51.1)(react-dom@19.1.0(react@19.1.0))(react@19.1.0): + dependencies: + '@babel/parser': 7.24.5 + '@babel/traverse': 7.25.6 + chalk: 4.1.2 + chokidar: 4.0.3 + commander: 11.1.0 + debounce: 2.0.0 + esbuild: 0.25.0 + glob: 10.3.4 + log-symbols: 4.1.0 + mime-types: 2.1.35 + next: 15.2.4(@babel/core@7.26.10)(@opentelemetry/api@1.9.0)(@playwright/test@1.51.1)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + normalize-path: 3.0.0 + ora: 5.4.1 + socket.io: 4.8.1 + transitivePeerDependencies: + - '@babel/core' + - '@opentelemetry/api' + - '@playwright/test' + - babel-plugin-macros + - babel-plugin-react-compiler + - bufferutil + - react + - react-dom + - sass + - supports-color + - utf-8-validate + react-github-btn@1.4.0(react@18.3.1): dependencies: github-buttons: 2.29.1 @@ -22720,6 +23776,10 @@ snapshots: react: 18.3.1 react-dom: 18.3.1(react@18.3.1) + react-promise-suspense@0.3.4: + dependencies: + fast-deep-equal: 2.0.1 + react-refresh@0.14.2: {} react-remove-scroll-bar@2.3.8(@types/react@18.3.20)(react@18.3.1): @@ -22783,6 +23843,8 @@ snapshots: dependencies: loose-envify: 1.4.0 + react@19.1.0: {} + read-cache@1.0.0: dependencies: pify: 2.3.0 @@ -22807,6 +23869,8 @@ snapshots: dependencies: picomatch: 2.3.1 + readdirp@4.1.2: {} + reading-time@1.5.0: {} recrawl-sync@2.2.3: @@ -23193,13 +24257,15 @@ snapshots: scheduler@0.25.0-rc-603e6108-20241029: {} + scheduler@0.26.0: {} + schema-utils@3.3.0: dependencies: '@types/json-schema': 7.0.15 ajv: 6.12.6 ajv-keywords: 3.5.2(ajv@6.12.6) - schema-utils@4.3.0: + schema-utils@4.3.1: dependencies: '@types/json-schema': 7.0.15 ajv: 8.17.1 @@ -23215,6 +24281,10 @@ snapshots: extend-shallow: 2.0.1 kind-of: 6.0.3 + selderee@0.11.0: + dependencies: + parseley: 0.12.1 + semver@6.3.1: {} semver@7.7.1: {} @@ -23424,6 +24494,36 @@ snapshots: is-plain-object: 5.0.0 tiny-warning: 1.0.3 + socket.io-adapter@2.5.5: + dependencies: + debug: 4.3.7 + ws: 8.17.1 + transitivePeerDependencies: + - bufferutil + - supports-color + - utf-8-validate + + socket.io-parser@4.2.4: + dependencies: + '@socket.io/component-emitter': 3.1.2 + debug: 4.3.7 + transitivePeerDependencies: + - supports-color + + socket.io@4.8.1: + dependencies: + accepts: 1.3.8 + base64id: 2.0.0 + cors: 2.8.5 + debug: 4.3.7 + engine.io: 6.6.4 + socket.io-adapter: 2.5.5 + socket.io-parser: 4.2.4 + transitivePeerDependencies: + - bufferutil + - supports-color + - utf-8-validate + sort-keys@5.1.0: dependencies: is-plain-obj: 4.1.0 @@ -23594,6 +24694,13 @@ snapshots: optionalDependencies: '@babel/core': 7.26.10 + styled-jsx@5.1.6(@babel/core@7.26.10)(react@19.1.0): + dependencies: + client-only: 0.0.1 + react: 19.1.0 + optionalDependencies: + '@babel/core': 7.26.10 + stylis@4.2.0: {} stylis@4.3.6: {} @@ -23694,7 +24801,7 @@ snapshots: dependencies: '@jridgewell/trace-mapping': 0.3.25 jest-worker: 27.5.1 - schema-utils: 4.3.0 + schema-utils: 4.3.1 serialize-javascript: 6.0.2 terser: 5.39.0 webpack: 5.98.0 @@ -23894,6 +25001,9 @@ snapshots: undici-types@6.20.0: {} + undici-types@6.21.0: + optional: true + undici@5.29.0: dependencies: '@fastify/busboy': 2.1.1 @@ -24182,13 +25292,13 @@ snapshots: - supports-color - terser - vite-node@2.1.9(@types/node@22.13.13)(terser@5.39.0): + vite-node@2.1.9(@types/node@22.14.1)(terser@5.39.0): dependencies: cac: 6.7.14 debug: 4.4.0 es-module-lexer: 1.6.0 pathe: 1.1.2 - vite: 5.4.15(@types/node@22.13.13)(terser@5.39.0) + vite: 5.4.15(@types/node@22.14.1)(terser@5.39.0) transitivePeerDependencies: - '@types/node' - less @@ -24208,21 +25318,21 @@ snapshots: rollup: 2.79.2 vite: 5.4.15(@types/node@20.17.28)(terser@5.39.0) - vite-plugin-eslint@1.8.1(eslint@8.57.1)(vite@5.4.15(@types/node@22.13.13)(terser@5.39.0)): + vite-plugin-eslint@1.8.1(eslint@8.57.1)(vite@5.4.15(@types/node@22.14.1)(terser@5.39.0)): dependencies: '@rollup/pluginutils': 4.2.1 '@types/eslint': 8.56.12 eslint: 8.57.1 rollup: 2.79.2 - vite: 5.4.15(@types/node@22.13.13)(terser@5.39.0) + vite: 5.4.15(@types/node@22.14.1)(terser@5.39.0) vite-plugin-externalize-deps@0.8.0(vite@5.4.15(@types/node@20.17.28)(terser@5.39.0)): dependencies: vite: 5.4.15(@types/node@20.17.28)(terser@5.39.0) - vite-plugin-externalize-deps@0.8.0(vite@5.4.15(@types/node@22.13.13)(terser@5.39.0)): + vite-plugin-externalize-deps@0.8.0(vite@5.4.15(@types/node@22.14.1)(terser@5.39.0)): dependencies: - vite: 5.4.15(@types/node@22.13.13)(terser@5.39.0) + vite: 5.4.15(@types/node@22.14.1)(terser@5.39.0) vite@5.4.15(@types/node@20.17.28)(terser@5.39.0): dependencies: @@ -24234,13 +25344,13 @@ snapshots: fsevents: 2.3.3 terser: 5.39.0 - vite@5.4.15(@types/node@22.13.13)(terser@5.39.0): + vite@5.4.15(@types/node@22.14.1)(terser@5.39.0): dependencies: esbuild: 0.21.5 postcss: 8.5.3 rollup: 4.37.0 optionalDependencies: - '@types/node': 22.13.13 + '@types/node': 22.14.1 fsevents: 2.3.3 terser: 5.39.0 @@ -24290,10 +25400,10 @@ snapshots: - supports-color - terser - vitest@2.1.9(@types/node@22.13.13)(@vitest/ui@2.1.9)(jsdom@21.1.2(canvas@2.11.2(encoding@0.1.13)))(terser@5.39.0): + vitest@2.1.9(@types/node@22.14.1)(@vitest/ui@2.1.9)(jsdom@21.1.2(canvas@2.11.2(encoding@0.1.13)))(terser@5.39.0): dependencies: '@vitest/expect': 2.1.9 - '@vitest/mocker': 2.1.9(vite@5.4.15(@types/node@22.13.13)(terser@5.39.0)) + '@vitest/mocker': 2.1.9(vite@5.4.15(@types/node@22.14.1)(terser@5.39.0)) '@vitest/pretty-format': 2.1.9 '@vitest/runner': 2.1.9 '@vitest/snapshot': 2.1.9 @@ -24309,11 +25419,11 @@ snapshots: tinyexec: 0.3.2 tinypool: 1.0.2 tinyrainbow: 1.2.0 - vite: 5.4.15(@types/node@22.13.13)(terser@5.39.0) - vite-node: 2.1.9(@types/node@22.13.13)(terser@5.39.0) + vite: 5.4.15(@types/node@22.14.1)(terser@5.39.0) + vite-node: 2.1.9(@types/node@22.14.1)(terser@5.39.0) why-is-node-running: 2.3.0 optionalDependencies: - '@types/node': 22.13.13 + '@types/node': 22.14.1 '@vitest/ui': 2.1.9(vitest@2.1.9) jsdom: 21.1.2(canvas@2.11.2(encoding@0.1.13)) transitivePeerDependencies: @@ -24327,10 +25437,10 @@ snapshots: - supports-color - terser - vitest@2.1.9(@types/node@22.13.13)(@vitest/ui@2.1.9)(jsdom@25.0.1(canvas@2.11.2(encoding@0.1.13)))(terser@5.39.0): + vitest@2.1.9(@types/node@22.14.1)(@vitest/ui@2.1.9)(jsdom@25.0.1(canvas@2.11.2(encoding@0.1.13)))(terser@5.39.0): dependencies: '@vitest/expect': 2.1.9 - '@vitest/mocker': 2.1.9(vite@5.4.15(@types/node@22.13.13)(terser@5.39.0)) + '@vitest/mocker': 2.1.9(vite@5.4.15(@types/node@22.14.1)(terser@5.39.0)) '@vitest/pretty-format': 2.1.9 '@vitest/runner': 2.1.9 '@vitest/snapshot': 2.1.9 @@ -24346,11 +25456,11 @@ snapshots: tinyexec: 0.3.2 tinypool: 1.0.2 tinyrainbow: 1.2.0 - vite: 5.4.15(@types/node@22.13.13)(terser@5.39.0) - vite-node: 2.1.9(@types/node@22.13.13)(terser@5.39.0) + vite: 5.4.15(@types/node@22.14.1)(terser@5.39.0) + vite-node: 2.1.9(@types/node@22.14.1)(terser@5.39.0) why-is-node-running: 2.3.0 optionalDependencies: - '@types/node': 22.13.13 + '@types/node': 22.14.1 '@vitest/ui': 2.1.9(vitest@2.1.9) jsdom: 25.0.1(canvas@2.11.2(encoding@0.1.13)) transitivePeerDependencies: @@ -24448,7 +25558,7 @@ snapshots: loader-runner: 4.3.0 mime-types: 2.1.35 neo-async: 2.6.2 - schema-utils: 4.3.0 + schema-utils: 4.3.1 tapable: 2.2.1 terser-webpack-plugin: 5.3.14(webpack@5.98.0) watchpack: 2.4.2 @@ -24576,6 +25686,8 @@ snapshots: ws@7.5.10: {} + ws@8.17.1: {} + ws@8.18.1: {} xml-formatter@3.6.5: From 06e8a4d6e997f47113f889761b8cb4a5acebff72 Mon Sep 17 00:00:00 2001 From: Nick the Sick Date: Wed, 23 Apr 2025 17:27:11 +0200 Subject: [PATCH 05/16] feat: implement github sponsors fallback --- docs/auth.ts | 162 +++++++++++++++++++- docs/components/example/index.tsx | 14 +- docs/package.json | 1 - docs/pages/pricing.mdx | 4 +- docs/util/auth-client.ts | 5 +- docs/util/product-list.ts | 19 +++ docs/util/send-mail.tsx | 85 ++++------- pnpm-lock.yaml | 242 +----------------------------- 8 files changed, 223 insertions(+), 309 deletions(-) create mode 100644 docs/util/product-list.ts diff --git a/docs/auth.ts b/docs/auth.ts index 63b3701a28..eff1451a05 100644 --- a/docs/auth.ts +++ b/docs/auth.ts @@ -1,10 +1,13 @@ import { polar } from "@polar-sh/better-auth"; import { Polar } from "@polar-sh/sdk"; import { betterAuth } from "better-auth"; +import { customSession } from "better-auth/plugins"; +import { github } from "better-auth/social-providers"; import { magicLink, openAPI } from "better-auth/plugins"; import Database from "better-sqlite3"; import { sendEmail } from "./util/send-mail"; +import { PRODUCTS } from "./util/product-list"; export const client = new Polar({ accessToken: process.env.POLAR_ACCESS_TOKEN, @@ -15,12 +18,21 @@ export const client = new Polar({ }); export const auth = betterAuth({ + user: { + additionalFields: { + ghSponsorPlanType: { + type: "string", + required: false, + input: false, // don't allow user to set role + }, + }, + }, emailVerification: { async sendVerificationEmail({ user, url }) { await sendEmail({ to: user.email, template: "verifyEmail", - props: { url }, + props: { url, name: user.name }, }); }, }, @@ -31,7 +43,7 @@ export const auth = betterAuth({ await sendEmail({ to: data.user.email, template: "resetPassword", - props: { url: data.url }, + props: { url: data.url, name: data.user.name }, }); }, }, @@ -39,10 +51,146 @@ export const auth = betterAuth({ github: { clientId: process.env.AUTH_GITHUB_ID as string, clientSecret: process.env.AUTH_GITHUB_SECRET as string, + async getUserInfo(token) { + // This is a workaround to still re-use the default github provider getUserInfo + // and still be able to fetch the sponsor info with the token + return (await github({ + clientId: process.env.AUTH_GITHUB_ID as string, + clientSecret: process.env.AUTH_GITHUB_SECRET as string, + async mapProfileToUser() { + const resSponsor = await fetch(`https://api.github.com/graphql`, { + method: "POST", + headers: { + "Content-Type": "application/json", + Authorization: `Bearer ${token.accessToken}`, + }, + // organization(login:"TypeCellOS") { + // user(login:"YousefED") { + body: JSON.stringify({ + query: `{ + user(login:"YousefED") { + sponsorshipForViewerAsSponsor(activeOnly:false) { + isActive, + tier { + name + monthlyPriceInDollars + } + } + } + }`, + }), + }); + + if (resSponsor.ok) { + // Mock data. TODO: disable and test actial data + // profile.sponsorInfo = { + // isActive: true, + // tier: { + // name: "test", + // monthlyPriceInDollars: 100, + // }, + // }; + // use API data: + + const data = await resSponsor.json(); + // eslint-disable-next-line no-console + console.log("sponsor data", data); + + // { + // "data": { + // "user": { + // "sponsorshipForViewerAsSponsor": { + // "isActive": true, + // "tier": { + // "name": "$90 a month", + // "monthlyPriceInDollars": 90 + // } + // } + // } + // } + // } + + const sponsorInfo: null | { + isActive: boolean; + tier: { + monthlyPriceInDollars: number; + }; + } = data.data.user.sponsorshipForViewerAsSponsor; + + if (!sponsorInfo?.isActive) { + return {}; + } + + return { + ghSponsorPlanType: + sponsorInfo.tier.monthlyPriceInDollars > 100 + ? "business" + : "starter", + }; + } + + return {}; + }, + }).getUserInfo(token))!; + }, }, }, database: new Database("./sqlite.db"), plugins: [ + customSession( + async ({ user, session }) => { + // Otherwise, check with Polar + const polarState = await client.customers.getStateExternal({ + externalId: user.id, + }); + + if ( + // No active subscriptions + !polarState.activeSubscriptions.length || + // Or, the subscription is not active + polarState.activeSubscriptions[0].status !== "active" + ) { + if (user.ghSponsorPlanType) { + // The user may be a GitHub sponsor plan type + return { + planType: user.ghSponsorPlanType, + user, + session, + }; + } + + return { + planType: PRODUCTS.free.slug, + user, + session, + }; + } + const subscription = polarState.activeSubscriptions[0]; + + const planType = Object.values(PRODUCTS).find( + (p) => p.id === subscription.productId, + )?.slug; + + // See if they are subscribed to a Polar product, if not, use the free plan + return { + planType: planType ?? PRODUCTS.free.slug, + user, + session, + }; + }, + { + // This is really only for type inference + user: { + additionalFields: { + ghSponsorPlanType: { + type: "string", + required: false, + input: false, // don't allow user to set role + }, + }, + }, + }, + ), magicLink({ sendMagicLink: async ({ email, url }) => { await sendEmail({ @@ -66,18 +214,18 @@ export const auth = betterAuth({ enabled: true, products: [ { - productId: "8049f66f-fd0a-4690-a0aa-442ac5b03040", // ID of Product from Polar Dashboard - slug: "business", // Custom slug for easy reference in Checkout URL, e.g. /checkout/pro + productId: PRODUCTS.business.id, // ID of Product from Polar Dashboard + slug: PRODUCTS.business.slug, // Custom slug for easy reference in Checkout URL, e.g. /checkout/pro // http://localhost:3000/api/auth/checkout/business }, { - productId: "ab70fea5-172c-4aac-b3fc-0824f2a5b670", - slug: "starter", + productId: PRODUCTS.starter.id, + slug: PRODUCTS.starter.slug, // http://localhost:3000/api/auth/checkout/starter }, ], // TODO set to actual page (welcome screen) - successUrl: "/success?checkout_id={CHECKOUT_ID}", + successUrl: "/?checkout_id={CHECKOUT_ID}", }, // Incoming Webhooks handler will be installed at /polar/webhooks webhooks: { diff --git a/docs/components/example/index.tsx b/docs/components/example/index.tsx index a1f5ee4e3d..19f7bfa348 100644 --- a/docs/components/example/index.tsx +++ b/docs/components/example/index.tsx @@ -1,23 +1,21 @@ -import { useSession } from "next-auth/react"; -// import { authClient } from "../../util/auth-client"; -import { examples } from "./generated/exampleComponents.gen"; import { authClient } from "@/util/auth-client"; +import { examples } from "./generated/exampleComponents.gen"; export function Example(props: { name: keyof typeof examples }) { - // authClient. - const session = authClient.useSession() - // const session = useSession(); + const session = authClient.useSession(); const example = examples[props.name]; if (!example) { throw new Error(`Example ${props.name} not found`); } const ExampleWithCode = example.ExampleWithCode; - // const userStatus = getProLevel(session); return ( ); } diff --git a/docs/package.json b/docs/package.json index 916cfa2447..125c2270d8 100644 --- a/docs/package.json +++ b/docs/package.json @@ -5,7 +5,6 @@ "scripts": { "dev": "next dev", "dev:email": "email dev", - "build:email": "email export --outDir ./", "build:site": "next build", "start": "next start", "lint": "next lint" diff --git a/docs/pages/pricing.mdx b/docs/pages/pricing.mdx index 699bd37636..b0f138a76a 100644 --- a/docs/pages/pricing.mdx +++ b/docs/pages/pricing.mdx @@ -28,7 +28,7 @@ export default function Pricing() { "Keep the open source library running and maintained", "XL packages available for open source projects under AGPL-3.0" ], - githubTierId: "291733", + href: "/api/auth/checkout/starter", }, { id: "tier-business", @@ -48,7 +48,7 @@ export default function Pricing() { "Access to a private Discord channel with the maintainers", "Up to 2 hours of individual support per month", ], - githubTierId: "440968", + href: "/api/auth/checkout/business", }, { id: "tier-enterprise", diff --git a/docs/util/auth-client.ts b/docs/util/auth-client.ts index a76177f15e..0c8a150b29 100644 --- a/docs/util/auth-client.ts +++ b/docs/util/auth-client.ts @@ -1,9 +1,10 @@ import { createAuthClient } from "better-auth/react"; - +import { customSessionClient } from "better-auth/client/plugins"; import { magicLinkClient } from "better-auth/client/plugins"; +import type { auth } from "@/auth"; export const authClient = createAuthClient({ - plugins: [magicLinkClient()], + plugins: [magicLinkClient(), customSessionClient()], }); export const { useSession, signIn, signOut, signUp } = authClient; diff --git a/docs/util/product-list.ts b/docs/util/product-list.ts new file mode 100644 index 0000000000..fc266a1766 --- /dev/null +++ b/docs/util/product-list.ts @@ -0,0 +1,19 @@ +export const PRODUCTS = { + business: { + id: "8049f66f-fd0a-4690-a0aa-442ac5b03040", + name: "Business", + slug: "business", + } as const, + starter: { + id: "ab70fea5-172c-4aac-b3fc-0824f2a5b670", + name: "Starter", + slug: "starter", + } as const, + free: { + id: "00000000-0000-0000-0000-000000000000", + name: "Free", + slug: "free", + } as const, +} as const; + +export type ProductSlug = (typeof PRODUCTS)[keyof typeof PRODUCTS]["slug"]; diff --git a/docs/util/send-mail.tsx b/docs/util/send-mail.tsx index 702f9378b1..661c7283e6 100644 --- a/docs/util/send-mail.tsx +++ b/docs/util/send-mail.tsx @@ -14,72 +14,53 @@ const transporter = nodemailer.createTransport({ }, }); -type TEMPLATES = { +const TEMPLATE_COMPONENTS = { verifyEmail: { - url: string; - name?: string; - }; + subject: "BlockNote - Verify your email address", + component: VerifyEmail, + }, resetPassword: { - url: string; - name?: string; - }; + subject: "BlockNote - Reset your password", + component: ResetPassword, + }, magicLink: { - url: string; - name?: string; - }; -}; - -const TEMPLATE_TEXTS = { - verifyEmail: (props: TEMPLATES["verifyEmail"]) => - render(, { - pretty: true, - plainText: true, - }), - resetPassword: (props: TEMPLATES["resetPassword"]) => - render(, { - pretty: true, - plainText: true, - }), - magicLink: (props: TEMPLATES["magicLink"]) => - render(, { - pretty: true, - plainText: true, - }), -}; -const TEMPLATE_HTMLS = { - verifyEmail: (props: TEMPLATES["verifyEmail"]) => - render(, { - pretty: true, - }), - resetPassword: (props: TEMPLATES["resetPassword"]) => - render(, { - pretty: true, - }), - magicLink: (props: TEMPLATES["magicLink"]): Promise => - render(, { - pretty: true, - }), -}; + subject: "BlockNote - Sign in to your account", + component: MagicLinkEmail, + }, +} as const; -export async function sendEmail({ +export async function sendEmail({ to, template, props, }: { to: string; template: T; - props: TEMPLATES[T]; + props: Parameters<(typeof TEMPLATE_COMPONENTS)[T]["component"]>[0]; }) { + if ( + !process.env.SMTP_HOST || + !process.env.SMTP_PORT || + !process.env.SMTP_USER || + !process.env.SMTP_PASS + ) { + console.log(template, props); + throw new Error( + "SMTP_HOST, SMTP_PORT, SMTP_USER, and SMTP_PASS must be set to send emails", + ); + } + const info = await transporter.sendMail({ from: '"BlockNote" ', to, - subject: { - verifyEmail: "BlockNote - Verify your email address", - resetPassword: "BlockNote - Reset your password", - magicLink: "BlockNote - Sign in to your account", - }[template], - text: await TEMPLATE_TEXTS[template](props), - html: await TEMPLATE_HTMLS[template](props), + subject: TEMPLATE_COMPONENTS[template].subject, + text: await render(TEMPLATE_COMPONENTS[template].component(props), { + pretty: true, + plainText: true, + }), + html: await render(TEMPLATE_COMPONENTS[template].component(props), { + pretty: true, + }), }); console.log("Email sent: ", info.messageId); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index b4f82ad6db..cc80841909 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -3079,28 +3079,6 @@ importers: specifier: ^5.3.3 version: 5.8.2 - packages/email: - dependencies: - '@react-email/components': - specifier: ^0.0.36 - version: 0.0.36(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - react: - specifier: ^19.1.0 - version: 19.1.0 - react-dom: - specifier: ^19.1.0 - version: 19.1.0(react@19.1.0) - devDependencies: - '@types/react': - specifier: ^19.1.2 - version: 19.1.2 - '@types/react-dom': - specifier: ^19.1.2 - version: 19.1.2(@types/react@19.1.2) - react-email: - specifier: ^4.0.7 - version: 4.0.7(@babel/core@7.26.10)(@opentelemetry/api@1.9.0)(@playwright/test@1.51.1)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - packages/mantine: dependencies: '@blocknote/core': @@ -7825,11 +7803,6 @@ packages: peerDependencies: '@types/react': ^18.0.0 - '@types/react-dom@19.1.2': - resolution: {integrity: sha512-XGJkWF41Qq305SKWEILa1O8vzhb3aOo3ogBlSmiqNko/WmRb6QIaweuZCXjKygVDXpzXb5wyxKTSOsmkuqj+Qw==} - peerDependencies: - '@types/react': ^19.0.0 - '@types/react-transition-group@4.4.12': resolution: {integrity: sha512-8TV6R3h2j7a91c+1DXdJi3Syo69zzIZbz7Lg5tORM5LEJG7X/E6a1V3drRyBRZq7/utz7A+c4OgYLiLcYGHG6w==} peerDependencies: @@ -12047,11 +12020,6 @@ packages: peerDependencies: react: ^18.3.1 - react-dom@19.1.0: - resolution: {integrity: sha512-Xs1hdnE+DyKgeHJeJznQmYMIBG3TKIHJJT95Q58nHLSrElKlGQqDTR2HQ9fx5CN/Gk6Vh/kupBTDLU11/nDk/g==} - peerDependencies: - react: ^19.1.0 - react-element-to-jsx-string@15.0.0: resolution: {integrity: sha512-UDg4lXB6BzlobN60P8fHWVPX3Kyw8ORrTeBtClmIlGdkOOE+GYQSFvmEU5iLLpwp/6v42DINwNcwOhOLfQ//FQ==} peerDependencies: @@ -12166,10 +12134,6 @@ packages: resolution: {integrity: sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==} engines: {node: '>=0.10.0'} - react@19.1.0: - resolution: {integrity: sha512-FS+XFBNvn3GTAWq26joslQgWNoFu08F4kl0J4CgdNKADkdSGXQyTCnKteIAJy96Br6YbpEU1LSzV5dYtjMkMDg==} - engines: {node: '>=0.10.0'} - read-cache@1.0.0: resolution: {integrity: sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==} @@ -12460,9 +12424,6 @@ packages: scheduler@0.25.0-rc-603e6108-20241029: resolution: {integrity: sha512-pFwF6H1XrSdYYNLfOcGlM28/j8CGLu8IvdrxqhjWULe2bPcKiKW4CV+OWqR/9fT52mywx65l7ysNkjLKBda7eA==} - scheduler@0.26.0: - resolution: {integrity: sha512-NlHwttCI/l5gCPR3D1nNXtWABUmBwvZpEQiD4IXSbIDq8BzLIK/7Ir5gTFSGZDUu37K5cMNp0hFtzO38sC7gWA==} - schema-utils@3.3.0: resolution: {integrity: sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==} engines: {node: '>= 10.13.0'} @@ -16970,44 +16931,23 @@ snapshots: dependencies: react: 18.3.1 - '@react-email/body@0.0.11(react@19.1.0)': - dependencies: - react: 19.1.0 - '@react-email/button@0.0.19(react@18.3.1)': dependencies: react: 18.3.1 - '@react-email/button@0.0.19(react@19.1.0)': - dependencies: - react: 19.1.0 - '@react-email/code-block@0.0.12(react@18.3.1)': dependencies: prismjs: 1.30.0 react: 18.3.1 - '@react-email/code-block@0.0.12(react@19.1.0)': - dependencies: - prismjs: 1.30.0 - react: 19.1.0 - '@react-email/code-inline@0.0.5(react@18.3.1)': dependencies: react: 18.3.1 - '@react-email/code-inline@0.0.5(react@19.1.0)': - dependencies: - react: 19.1.0 - '@react-email/column@0.0.13(react@18.3.1)': dependencies: react: 18.3.1 - '@react-email/column@0.0.13(react@19.1.0)': - dependencies: - react: 19.1.0 - '@react-email/components@0.0.36(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: '@react-email/body': 0.0.11(react@18.3.1) @@ -17034,114 +16974,47 @@ snapshots: transitivePeerDependencies: - react-dom - '@react-email/components@0.0.36(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': - dependencies: - '@react-email/body': 0.0.11(react@19.1.0) - '@react-email/button': 0.0.19(react@19.1.0) - '@react-email/code-block': 0.0.12(react@19.1.0) - '@react-email/code-inline': 0.0.5(react@19.1.0) - '@react-email/column': 0.0.13(react@19.1.0) - '@react-email/container': 0.0.15(react@19.1.0) - '@react-email/font': 0.0.9(react@19.1.0) - '@react-email/head': 0.0.12(react@19.1.0) - '@react-email/heading': 0.0.15(react@19.1.0) - '@react-email/hr': 0.0.11(react@19.1.0) - '@react-email/html': 0.0.11(react@19.1.0) - '@react-email/img': 0.0.11(react@19.1.0) - '@react-email/link': 0.0.12(react@19.1.0) - '@react-email/markdown': 0.0.14(react@19.1.0) - '@react-email/preview': 0.0.12(react@19.1.0) - '@react-email/render': 1.0.6(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@react-email/row': 0.0.12(react@19.1.0) - '@react-email/section': 0.0.16(react@19.1.0) - '@react-email/tailwind': 1.0.4(react@19.1.0) - '@react-email/text': 0.1.1(react@19.1.0) - react: 19.1.0 - transitivePeerDependencies: - - react-dom - '@react-email/container@0.0.15(react@18.3.1)': dependencies: react: 18.3.1 - '@react-email/container@0.0.15(react@19.1.0)': - dependencies: - react: 19.1.0 - '@react-email/font@0.0.9(react@18.3.1)': dependencies: react: 18.3.1 - '@react-email/font@0.0.9(react@19.1.0)': - dependencies: - react: 19.1.0 - '@react-email/head@0.0.12(react@18.3.1)': dependencies: react: 18.3.1 - '@react-email/head@0.0.12(react@19.1.0)': - dependencies: - react: 19.1.0 - '@react-email/heading@0.0.15(react@18.3.1)': dependencies: react: 18.3.1 - '@react-email/heading@0.0.15(react@19.1.0)': - dependencies: - react: 19.1.0 - '@react-email/hr@0.0.11(react@18.3.1)': dependencies: react: 18.3.1 - '@react-email/hr@0.0.11(react@19.1.0)': - dependencies: - react: 19.1.0 - '@react-email/html@0.0.11(react@18.3.1)': dependencies: react: 18.3.1 - '@react-email/html@0.0.11(react@19.1.0)': - dependencies: - react: 19.1.0 - '@react-email/img@0.0.11(react@18.3.1)': dependencies: react: 18.3.1 - '@react-email/img@0.0.11(react@19.1.0)': - dependencies: - react: 19.1.0 - '@react-email/link@0.0.12(react@18.3.1)': dependencies: react: 18.3.1 - '@react-email/link@0.0.12(react@19.1.0)': - dependencies: - react: 19.1.0 - '@react-email/markdown@0.0.14(react@18.3.1)': dependencies: md-to-react-email: 5.0.5(react@18.3.1) react: 18.3.1 - '@react-email/markdown@0.0.14(react@19.1.0)': - dependencies: - md-to-react-email: 5.0.5(react@19.1.0) - react: 19.1.0 - '@react-email/preview@0.0.12(react@18.3.1)': dependencies: react: 18.3.1 - '@react-email/preview@0.0.12(react@19.1.0)': - dependencies: - react: 19.1.0 - '@react-email/render@1.0.6(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: html-to-text: 9.0.5 @@ -17150,46 +17023,22 @@ snapshots: react-dom: 18.3.1(react@18.3.1) react-promise-suspense: 0.3.4 - '@react-email/render@1.0.6(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': - dependencies: - html-to-text: 9.0.5 - prettier: 3.5.3 - react: 19.1.0 - react-dom: 19.1.0(react@19.1.0) - react-promise-suspense: 0.3.4 - '@react-email/row@0.0.12(react@18.3.1)': dependencies: react: 18.3.1 - '@react-email/row@0.0.12(react@19.1.0)': - dependencies: - react: 19.1.0 - '@react-email/section@0.0.16(react@18.3.1)': dependencies: react: 18.3.1 - '@react-email/section@0.0.16(react@19.1.0)': - dependencies: - react: 19.1.0 - '@react-email/tailwind@1.0.4(react@18.3.1)': dependencies: react: 18.3.1 - '@react-email/tailwind@1.0.4(react@19.1.0)': - dependencies: - react: 19.1.0 - '@react-email/text@0.1.1(react@18.3.1)': dependencies: react: 18.3.1 - '@react-email/text@0.1.1(react@19.1.0)': - dependencies: - react: 19.1.0 - '@react-pdf/fns@3.1.2': {} '@react-pdf/font@4.0.2': @@ -18355,10 +18204,6 @@ snapshots: dependencies: '@types/react': 18.3.20 - '@types/react-dom@19.1.2(@types/react@19.1.2)': - dependencies: - '@types/react': 19.1.2 - '@types/react-transition-group@4.4.12(@types/react@18.3.20)': dependencies: '@types/react': 18.3.20 @@ -20330,7 +20175,7 @@ snapshots: '@typescript-eslint/parser': 5.62.0(eslint@8.57.1)(typescript@5.8.2) eslint: 8.57.1 eslint-import-resolver-node: 0.3.9 - eslint-import-resolver-typescript: 3.10.0(eslint-plugin-import@2.31.0)(eslint@8.57.1) + eslint-import-resolver-typescript: 3.10.0(eslint-plugin-import@2.31.0(@typescript-eslint/parser@5.62.0(eslint@8.57.1)(typescript@5.8.2))(eslint@8.57.1))(eslint@8.57.1) eslint-plugin-import: 2.31.0(@typescript-eslint/parser@5.62.0(eslint@8.57.1)(typescript@5.8.2))(eslint-import-resolver-typescript@3.10.0)(eslint@8.57.1) eslint-plugin-jsx-a11y: 6.10.2(eslint@8.57.1) eslint-plugin-react: 7.37.4(eslint@8.57.1) @@ -20377,7 +20222,7 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-import-resolver-typescript@3.10.0(eslint-plugin-import@2.31.0)(eslint@8.57.1): + eslint-import-resolver-typescript@3.10.0(eslint-plugin-import@2.31.0(@typescript-eslint/parser@5.62.0(eslint@8.57.1)(typescript@5.8.2))(eslint@8.57.1))(eslint@8.57.1): dependencies: '@nolyfill/is-core-module': 1.0.39 debug: 4.4.0 @@ -20392,14 +20237,14 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-module-utils@2.12.0(@typescript-eslint/parser@5.62.0(eslint@8.57.1)(typescript@5.8.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.0)(eslint@8.57.1): + eslint-module-utils@2.12.0(@typescript-eslint/parser@5.62.0(eslint@8.57.1)(typescript@5.8.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.0(eslint-plugin-import@2.31.0(@typescript-eslint/parser@5.62.0(eslint@8.57.1)(typescript@5.8.2))(eslint@8.57.1))(eslint@8.57.1))(eslint@8.57.1): dependencies: debug: 3.2.7 optionalDependencies: '@typescript-eslint/parser': 5.62.0(eslint@8.57.1)(typescript@5.8.2) eslint: 8.57.1 eslint-import-resolver-node: 0.3.9 - eslint-import-resolver-typescript: 3.10.0(eslint-plugin-import@2.31.0)(eslint@8.57.1) + eslint-import-resolver-typescript: 3.10.0(eslint-plugin-import@2.31.0(@typescript-eslint/parser@5.62.0(eslint@8.57.1)(typescript@5.8.2))(eslint@8.57.1))(eslint@8.57.1) transitivePeerDependencies: - supports-color @@ -20422,7 +20267,7 @@ snapshots: doctrine: 2.1.0 eslint: 8.57.1 eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.12.0(@typescript-eslint/parser@5.62.0(eslint@8.57.1)(typescript@5.8.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.0)(eslint@8.57.1) + eslint-module-utils: 2.12.0(@typescript-eslint/parser@5.62.0(eslint@8.57.1)(typescript@5.8.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.0(eslint-plugin-import@2.31.0(@typescript-eslint/parser@5.62.0(eslint@8.57.1)(typescript@5.8.2))(eslint@8.57.1))(eslint@8.57.1))(eslint@8.57.1) hasown: 2.0.2 is-core-module: 2.16.1 is-glob: 4.0.3 @@ -21920,11 +21765,6 @@ snapshots: marked: 7.0.4 react: 18.3.1 - md-to-react-email@5.0.5(react@19.1.0): - dependencies: - marked: 7.0.4 - react: 19.1.0 - mdast-util-definitions@5.1.2: dependencies: '@types/mdast': 3.0.15 @@ -22892,33 +22732,6 @@ snapshots: - '@babel/core' - babel-plugin-macros - next@15.2.4(@babel/core@7.26.10)(@opentelemetry/api@1.9.0)(@playwright/test@1.51.1)(react-dom@19.1.0(react@19.1.0))(react@19.1.0): - dependencies: - '@next/env': 15.2.4 - '@swc/counter': 0.1.3 - '@swc/helpers': 0.5.15 - busboy: 1.6.0 - caniuse-lite: 1.0.30001707 - postcss: 8.4.31 - react: 19.1.0 - react-dom: 19.1.0(react@19.1.0) - styled-jsx: 5.1.6(@babel/core@7.26.10)(react@19.1.0) - optionalDependencies: - '@next/swc-darwin-arm64': 15.2.4 - '@next/swc-darwin-x64': 15.2.4 - '@next/swc-linux-arm64-gnu': 15.2.4 - '@next/swc-linux-arm64-musl': 15.2.4 - '@next/swc-linux-x64-gnu': 15.2.4 - '@next/swc-linux-x64-musl': 15.2.4 - '@next/swc-win32-arm64-msvc': 15.2.4 - '@next/swc-win32-x64-msvc': 15.2.4 - '@opentelemetry/api': 1.9.0 - '@playwright/test': 1.51.1 - sharp: 0.33.5 - transitivePeerDependencies: - - '@babel/core' - - babel-plugin-macros - nextra-theme-docs@2.13.4(next@15.2.4(@babel/core@7.26.10)(@opentelemetry/api@1.9.0)(@playwright/test@1.51.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(nextra@2.13.4(next@15.2.4(@babel/core@7.26.10)(@opentelemetry/api@1.9.0)(@playwright/test@1.51.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1): dependencies: '@headlessui/react': 1.7.19(react-dom@18.3.1(react@18.3.1))(react@18.3.1) @@ -23677,11 +23490,6 @@ snapshots: react: 18.3.1 scheduler: 0.23.2 - react-dom@19.1.0(react@19.1.0): - dependencies: - react: 19.1.0 - scheduler: 0.26.0 - react-element-to-jsx-string@15.0.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1): dependencies: '@base2/pretty-print-object': 1.0.1 @@ -23719,35 +23527,6 @@ snapshots: - supports-color - utf-8-validate - react-email@4.0.7(@babel/core@7.26.10)(@opentelemetry/api@1.9.0)(@playwright/test@1.51.1)(react-dom@19.1.0(react@19.1.0))(react@19.1.0): - dependencies: - '@babel/parser': 7.24.5 - '@babel/traverse': 7.25.6 - chalk: 4.1.2 - chokidar: 4.0.3 - commander: 11.1.0 - debounce: 2.0.0 - esbuild: 0.25.0 - glob: 10.3.4 - log-symbols: 4.1.0 - mime-types: 2.1.35 - next: 15.2.4(@babel/core@7.26.10)(@opentelemetry/api@1.9.0)(@playwright/test@1.51.1)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - normalize-path: 3.0.0 - ora: 5.4.1 - socket.io: 4.8.1 - transitivePeerDependencies: - - '@babel/core' - - '@opentelemetry/api' - - '@playwright/test' - - babel-plugin-macros - - babel-plugin-react-compiler - - bufferutil - - react - - react-dom - - sass - - supports-color - - utf-8-validate - react-github-btn@1.4.0(react@18.3.1): dependencies: github-buttons: 2.29.1 @@ -23843,8 +23622,6 @@ snapshots: dependencies: loose-envify: 1.4.0 - react@19.1.0: {} - read-cache@1.0.0: dependencies: pify: 2.3.0 @@ -24257,8 +24034,6 @@ snapshots: scheduler@0.25.0-rc-603e6108-20241029: {} - scheduler@0.26.0: {} - schema-utils@3.3.0: dependencies: '@types/json-schema': 7.0.15 @@ -24694,13 +24469,6 @@ snapshots: optionalDependencies: '@babel/core': 7.26.10 - styled-jsx@5.1.6(@babel/core@7.26.10)(react@19.1.0): - dependencies: - client-only: 0.0.1 - react: 19.1.0 - optionalDependencies: - '@babel/core': 7.26.10 - stylis@4.2.0: {} stylis@4.3.6: {} From d64c270bf8131d796dab9c43f2dd46afc424e3f1 Mon Sep 17 00:00:00 2001 From: Nick the Sick Date: Thu, 24 Apr 2025 14:59:13 +0200 Subject: [PATCH 06/16] feat: use supabase or any PG db --- docs/.env.local.example | 1 + docs/auth.ts | 74 ++++++++++------- docs/package.json | 4 +- docs/util/send-mail.tsx | 31 ++++--- package.json | 3 +- pnpm-lock.yaml | 176 ++++++++++++++++++++++++++++++---------- 6 files changed, 198 insertions(+), 91 deletions(-) diff --git a/docs/.env.local.example b/docs/.env.local.example index e9dcc0e453..0b6aca8e63 100644 --- a/docs/.env.local.example +++ b/docs/.env.local.example @@ -16,6 +16,7 @@ SMTP_SECURE=false # Better Auth BETTER_AUTH_SECRET= # Linux: `openssl rand -hex 32` or go to https://generate-secret.vercel.app/32 BETTER_AUTH_URL=http://localhost:3000 +POSTGRES_URL= # Polar POLAR_ACCESS_TOKEN= diff --git a/docs/auth.ts b/docs/auth.ts index eff1451a05..f98cd1311e 100644 --- a/docs/auth.ts +++ b/docs/auth.ts @@ -1,20 +1,20 @@ import { polar } from "@polar-sh/better-auth"; import { Polar } from "@polar-sh/sdk"; +import * as Sentry from "@sentry/nextjs"; import { betterAuth } from "better-auth"; -import { customSession } from "better-auth/plugins"; +import { customSession, magicLink, openAPI } from "better-auth/plugins"; import { github } from "better-auth/social-providers"; -import { magicLink, openAPI } from "better-auth/plugins"; -import Database from "better-sqlite3"; +import { Pool } from "pg"; -import { sendEmail } from "./util/send-mail"; import { PRODUCTS } from "./util/product-list"; +import { sendEmail } from "./util/send-mail"; export const client = new Polar({ accessToken: process.env.POLAR_ACCESS_TOKEN, // Use 'sandbox' if you're using the Polar Sandbox environment // Remember that access tokens, products, etc. are completely separated between environments. // Access tokens obtained in Production are for instance not usable in the Sandbox environment. - server: "sandbox", + server: process.env.NODE_ENV === "production" ? "production" : "sandbox", }); export const auth = betterAuth({ @@ -135,29 +135,53 @@ export const auth = betterAuth({ }, }, }, - database: new Database("./sqlite.db"), + database: new Pool({ + connectionString: process.env.POSTGRES_URL, + }), plugins: [ customSession( async ({ user, session }) => { - // Otherwise, check with Polar - const polarState = await client.customers.getStateExternal({ - externalId: user.id, - }); + try { + // Check for a Polar subscription + const polarState = await client.customers.getStateExternal({ + externalId: user.id, + }); + + if ( + // No active subscriptions + !polarState.activeSubscriptions.length || + // Or, the subscription is not active + polarState.activeSubscriptions[0].status !== "active" + ) { + if (user.ghSponsorPlanType) { + // The user may be a GitHub sponsor plan type + return { + planType: user.ghSponsorPlanType, + user, + session, + }; + } - if ( - // No active subscriptions - !polarState.activeSubscriptions.length || - // Or, the subscription is not active - polarState.activeSubscriptions[0].status !== "active" - ) { - if (user.ghSponsorPlanType) { - // The user may be a GitHub sponsor plan type return { - planType: user.ghSponsorPlanType, + planType: PRODUCTS.free.slug, user, session, }; } + const subscription = polarState.activeSubscriptions[0]; + + const planType = Object.values(PRODUCTS).find( + (p) => p.id === subscription.productId, + )?.slug; + + // See if they are subscribed to a Polar product, if not, use the free plan + return { + planType: planType ?? PRODUCTS.free.slug, + user, + session, + }; + } catch (err) { + Sentry.captureException(err); return { planType: PRODUCTS.free.slug, @@ -165,18 +189,6 @@ export const auth = betterAuth({ session, }; } - const subscription = polarState.activeSubscriptions[0]; - - const planType = Object.values(PRODUCTS).find( - (p) => p.id === subscription.productId, - )?.slug; - - // See if they are subscribed to a Polar product, if not, use the free plan - return { - planType: planType ?? PRODUCTS.free.slug, - user, - session, - }; }, { // This is really only for type inference diff --git a/docs/package.json b/docs/package.json index 125c2270d8..fe9867c3f0 100644 --- a/docs/package.json +++ b/docs/package.json @@ -26,12 +26,10 @@ "@polar-sh/sdk": "^0.32.11", "@react-email/render": "1.0.6", "@sentry/nextjs": "9.4.0", - "@types/better-sqlite3": "7.6.13", "@types/nodemailer": "6.4.17", "@vercel/analytics": "^1.2.2", "@vercel/og": "^0.6.2", "better-auth": "1.2.7", - "better-sqlite3": "11.9.1", "classnames": "2.3.2", "clsx": "^2.1.0", "framer-motion": "^10.16.16", @@ -41,6 +39,7 @@ "nextra-theme-docs": "^2.13.2", "nodemailer": "6.10.1", "partykit": "^0.0.84", + "pg": "8.15.5", "raw-loader": "^4.0.2", "react": "^18.3.1", "react-dom": "^18.3.1", @@ -53,6 +52,7 @@ "devDependencies": { "@react-email/components": "^0.0.36", "@types/node": "^20", + "@types/pg": "8.11.14", "@types/react": "^18.0.25", "@types/react-dom": "^18.0.9", "autoprefixer": "^10.0.1", diff --git a/docs/util/send-mail.tsx b/docs/util/send-mail.tsx index 661c7283e6..0afd21fe59 100644 --- a/docs/util/send-mail.tsx +++ b/docs/util/send-mail.tsx @@ -3,6 +3,7 @@ import { render } from "@react-email/render"; import MagicLinkEmail from "@/emails/magic-link"; import VerifyEmail from "@/emails/verify-email"; import ResetPassword from "@/emails/reset-password"; +import * as Sentry from "@sentry/nextjs"; const transporter = nodemailer.createTransport({ host: String(process.env.SMTP_HOST), @@ -50,18 +51,22 @@ export async function sendEmail({ ); } - const info = await transporter.sendMail({ - from: '"BlockNote" ', - to, - subject: TEMPLATE_COMPONENTS[template].subject, - text: await render(TEMPLATE_COMPONENTS[template].component(props), { - pretty: true, - plainText: true, - }), - html: await render(TEMPLATE_COMPONENTS[template].component(props), { - pretty: true, - }), - }); + try { + const info = await transporter.sendMail({ + from: '"BlockNote" ', + to, + subject: TEMPLATE_COMPONENTS[template].subject, + text: await render(TEMPLATE_COMPONENTS[template].component(props), { + pretty: true, + plainText: true, + }), + html: await render(TEMPLATE_COMPONENTS[template].component(props), { + pretty: true, + }), + }); - console.log("Email sent: ", info.messageId); + console.log("Email sent: ", info.messageId); + } catch (err) { + Sentry.captureException(err); + } } diff --git a/package.json b/package.json index 3618f79eb6..36dc29bac9 100644 --- a/package.json +++ b/package.json @@ -27,8 +27,7 @@ "@sentry/cli", "canvas", "esbuild", - "nx", - "better-sqlite3" + "nx" ] }, "packageManager": "pnpm@10.7.1+sha512.2d92c86b7928dc8284f53494fb4201f983da65f0fb4f0d40baafa5cf628fa31dae3e5968f12466f17df7e97310e30f343a648baea1b9b350685dafafffdf5808", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index cc80841909..77d26bf446 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -104,9 +104,6 @@ importers: '@sentry/nextjs': specifier: 9.4.0 version: 9.4.0(@opentelemetry/context-async-hooks@1.30.1(@opentelemetry/api@1.9.0))(@opentelemetry/core@1.30.1(@opentelemetry/api@1.9.0))(@opentelemetry/instrumentation@0.57.2(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@1.30.1(@opentelemetry/api@1.9.0))(encoding@0.1.13)(next@15.2.4(@babel/core@7.26.10)(@opentelemetry/api@1.9.0)(@playwright/test@1.51.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1)(webpack@5.98.0) - '@types/better-sqlite3': - specifier: 7.6.13 - version: 7.6.13 '@types/nodemailer': specifier: 6.4.17 version: 6.4.17 @@ -119,9 +116,6 @@ importers: better-auth: specifier: 1.2.7 version: 1.2.7 - better-sqlite3: - specifier: 11.9.1 - version: 11.9.1 classnames: specifier: 2.3.2 version: 2.3.2 @@ -149,6 +143,9 @@ importers: partykit: specifier: ^0.0.84 version: 0.0.84 + pg: + specifier: 8.15.5 + version: 8.15.5 raw-loader: specifier: ^4.0.2 version: 4.0.2(webpack@5.98.0) @@ -180,6 +177,9 @@ importers: '@types/node': specifier: ^20 version: 20.17.28 + '@types/pg': + specifier: 8.11.14 + version: 8.11.14 '@types/react': specifier: ^18.0.25 version: 18.3.20 @@ -7651,9 +7651,6 @@ packages: '@types/babel__traverse@7.20.7': resolution: {integrity: sha512-dkO5fhS7+/oos4ciWxyEyjWe48zmG6wbCheo/G2ZnHx4fs3EU6YC6UM8rk56gAjNJ9P3MTH2jo5jb92/K6wbng==} - '@types/better-sqlite3@7.6.13': - resolution: {integrity: sha512-NMv9ASNARoKksWtsq/SHakpYAYnhBrQgGD8zkLYk/jaK8jUGn08CfEdTRgYhMypUQAfzSP8W6gNLe0q19/t4VA==} - '@types/connect@3.4.38': resolution: {integrity: sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==} @@ -7789,6 +7786,9 @@ packages: '@types/pg-pool@2.0.6': resolution: {integrity: sha512-TaAUE5rq2VQYxab5Ts7WZhKNmuN78Q6PiFonTDdpbx8a1H0M1vhy3rhiMjl+e2iHmogyMw7jZF4FrE6eJUy5HQ==} + '@types/pg@8.11.14': + resolution: {integrity: sha512-qyD11E5R3u0eJmd1lB0WnWKXJGA7s015nyARWljfz5DcX83TKAIlY+QrmvzQTsbIe+hkiFtkyL2gHC6qwF6Fbg==} + '@types/pg@8.6.1': resolution: {integrity: sha512-1Kc4oAGzAl7uqUStZCDvaLFqZrW9qWSjXOmBfdgyBP5La7Us6Mg4GBvRlSoaZMhQF/zSj1C8CtKMBkoiT8eL8w==} @@ -8539,9 +8539,6 @@ packages: better-call@1.0.8: resolution: {integrity: sha512-/PV8JLqDRUN7JyBPbklVsS/8E4SO3pnf8hbpa8B7xrBrr+BBYpeOAxoqtnsyk/pRs35vNB4MZx8cn9dBuNlLDA==} - better-sqlite3@11.9.1: - resolution: {integrity: sha512-Ba0KR+Fzxh2jDRhdg6TSH0SJGzb8C0aBY4hR8w8madIdIzzC6Y1+kx5qR6eS1Z+Gy20h6ZU28aeyg0z1VIrShQ==} - bidi-js@1.0.3: resolution: {integrity: sha512-RKshQI1R3YQ+n9YJz2QQ147P66ELpa1FQEg20Dk8oW9t2KgLbpDLLp9aGZ7y8WHSshDknG0bknqGw5/tyCs5tw==} @@ -8552,9 +8549,6 @@ packages: resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==} engines: {node: '>=8'} - bindings@1.5.0: - resolution: {integrity: sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==} - bl@4.1.0: resolution: {integrity: sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==} @@ -9752,9 +9746,6 @@ packages: resolution: {integrity: sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==} engines: {node: ^10.12.0 || >=12.0.0} - file-uri-to-path@1.0.0: - resolution: {integrity: sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==} - filelist@1.0.4: resolution: {integrity: sha512-w1cEuf3S+DrLCQL7ET6kz+gmlJdbq9J7yXCSjK/OZCPA+qEN1WyF4ZAf0YYJa4/shHJra2t/d/r8SV4Ji+x+8Q==} @@ -11451,6 +11442,9 @@ packages: resolution: {integrity: sha512-gXah6aZrcUxjWg2zR2MwouP2eHlCBzdV4pygudehaKXSGW4v2AsRQUK+lwwXhii6KFZcunEnmSUoYp5CXibxtA==} engines: {node: '>= 0.4'} + obuf@1.1.2: + resolution: {integrity: sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==} + on-headers@1.0.2: resolution: {integrity: sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==} engines: {node: '>= 0.8'} @@ -11631,17 +11625,48 @@ packages: periscopic@3.1.0: resolution: {integrity: sha512-vKiQ8RRtkl9P+r/+oefh25C3fhybptkHKCZSPlcXiJux2tJF55GnEj3BVn4A5gKfq9NWWXXrxkHBwVPUfH0opw==} + pg-cloudflare@1.2.5: + resolution: {integrity: sha512-OOX22Vt0vOSRrdoUPKJ8Wi2OpE/o/h9T8X1s4qSkCedbNah9ei2W2765be8iMVxQUsvgT7zIAT2eIa9fs5+vtg==} + + pg-connection-string@2.8.5: + resolution: {integrity: sha512-Ni8FuZ8yAF+sWZzojvtLE2b03cqjO5jNULcHFfM9ZZ0/JXrgom5pBREbtnAw7oxsxJqHw9Nz/XWORUEL3/IFow==} + pg-int8@1.0.1: resolution: {integrity: sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==} engines: {node: '>=4.0.0'} - pg-protocol@1.8.0: - resolution: {integrity: sha512-jvuYlEkL03NRvOoyoRktBK7+qU5kOvlAwvmrH8sr3wbLrOdVWsRxQfz8mMy9sZFsqJ1hEWNfdWKI4SAmoL+j7g==} + pg-numeric@1.0.2: + resolution: {integrity: sha512-BM/Thnrw5jm2kKLE5uJkXqqExRUY/toLHda65XgFTBTFYZyopbKjBe29Ii3RbkvlsMoFwD+tHeGaCjjv0gHlyw==} + engines: {node: '>=4'} + + pg-pool@3.9.5: + resolution: {integrity: sha512-DxyAlOgvUzRFpFAZjbCc8fUfG7BcETDHgepFPf724B0i08k9PAiZV1tkGGgQIL0jbMEuR9jW1YN7eX+WgXxCsQ==} + peerDependencies: + pg: '>=8.0' + + pg-protocol@1.9.5: + resolution: {integrity: sha512-DYTWtWpfd5FOro3UnAfwvhD8jh59r2ig8bPtc9H8Ds7MscE/9NYruUQWFAOuraRl29jwcT2kyMFQ3MxeaVjUhg==} pg-types@2.2.0: resolution: {integrity: sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==} engines: {node: '>=4'} + pg-types@4.0.2: + resolution: {integrity: sha512-cRL3JpS3lKMGsKaWndugWQoLOCoP+Cic8oseVcbr0qhPzYD5DWXK+RZ9LY9wxRf7RQia4SCwQlXk0q6FCPrVng==} + engines: {node: '>=10'} + + pg@8.15.5: + resolution: {integrity: sha512-EpAhHFQc+aH9VfeffWIVC+XXk6lmAhS9W1FxtxcPXs94yxhrI1I6w/zkWfIOII/OkBv3Be04X3xMOj0kQ78l6w==} + engines: {node: '>= 8.0.0'} + peerDependencies: + pg-native: '>=3.0.1' + peerDependenciesMeta: + pg-native: + optional: true + + pgpass@1.0.5: + resolution: {integrity: sha512-FdW9r/jQZhSeohs1Z3sI1yxFQNFvMcnmfuj4WBMUTxOrAyLMaTcE1aAMBiTlbMNaXvBCQuVi0R7hd8udDSP7ug==} + picocolors@1.1.1: resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} @@ -11736,18 +11761,37 @@ packages: resolution: {integrity: sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA==} engines: {node: '>=4'} + postgres-array@3.0.4: + resolution: {integrity: sha512-nAUSGfSDGOaOAEGwqsRY27GPOea7CNipJPOA7lPbdEpx5Kg3qzdP0AaWC5MlhTWV9s4hFX39nomVZ+C4tnGOJQ==} + engines: {node: '>=12'} + postgres-bytea@1.0.0: resolution: {integrity: sha512-xy3pmLuQqRBZBXDULy7KbaitYqLcmxigw14Q5sj8QBVLqEwXfeybIKVWiqAXTlcvdvb0+xkOtDbfQMOf4lST1w==} engines: {node: '>=0.10.0'} + postgres-bytea@3.0.0: + resolution: {integrity: sha512-CNd4jim9RFPkObHSjVHlVrxoVQXz7quwNFpz7RY1okNNme49+sVyiTvTRobiLV548Hx/hb1BG+iE7h9493WzFw==} + engines: {node: '>= 6'} + postgres-date@1.0.7: resolution: {integrity: sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q==} engines: {node: '>=0.10.0'} + postgres-date@2.1.0: + resolution: {integrity: sha512-K7Juri8gtgXVcDfZttFKVmhglp7epKb1K4pgrkLxehjqkrgPhfG6OO8LHLkfaqkbpjNRnra018XwAr1yQFWGcA==} + engines: {node: '>=12'} + postgres-interval@1.2.0: resolution: {integrity: sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==} engines: {node: '>=0.10.0'} + postgres-interval@3.0.0: + resolution: {integrity: sha512-BSNDnbyZCXSxgA+1f5UU2GmwhoI0aU5yMxRGO8CdFEcY2BQF9xm/7MqKnYoM1nJDk8nONNWDk9WeSmePFhQdlw==} + engines: {node: '>=12'} + + postgres-range@1.1.4: + resolution: {integrity: sha512-i/hbxIE9803Alj/6ytL7UHQxRvZkI9O4Sy+J3HGc4F4oo/2eQAjTSNJ0bfxyse3bH0nuVesCk+3IRLaMtG3H6w==} + preact-render-to-string@5.2.3: resolution: {integrity: sha512-aPDxUn5o3GhWdtJtW0svRC2SS/l8D9MAgo2+AWml+BhDImb27ALf04Q2d+AHqUUOc6RdSXFIBVa2gxzgMKgtZA==} peerDependencies: @@ -12623,6 +12667,10 @@ packages: space-separated-tokens@2.0.2: resolution: {integrity: sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==} + split2@4.2.0: + resolution: {integrity: sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==} + engines: {node: '>= 10.x'} + sprintf-js@1.0.3: resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==} @@ -18026,10 +18074,6 @@ snapshots: dependencies: '@babel/types': 7.27.0 - '@types/better-sqlite3@7.6.13': - dependencies: - '@types/node': 20.17.30 - '@types/connect@3.4.38': dependencies: '@types/node': 20.17.30 @@ -18186,12 +18230,18 @@ snapshots: '@types/pg-pool@2.0.6': dependencies: - '@types/pg': 8.6.1 + '@types/pg': 8.11.14 + + '@types/pg@8.11.14': + dependencies: + '@types/node': 20.17.30 + pg-protocol: 1.9.5 + pg-types: 4.0.2 '@types/pg@8.6.1': dependencies: '@types/node': 20.17.30 - pg-protocol: 1.8.0 + pg-protocol: 1.9.5 pg-types: 2.2.0 '@types/pixelmatch@5.2.6': @@ -19072,11 +19122,6 @@ snapshots: set-cookie-parser: 2.7.1 uncrypto: 0.1.3 - better-sqlite3@11.9.1: - dependencies: - bindings: 1.5.0 - prebuild-install: 7.1.3 - bidi-js@1.0.3: dependencies: require-from-string: 2.0.2 @@ -19085,10 +19130,6 @@ snapshots: binary-extensions@2.3.0: {} - bindings@1.5.0: - dependencies: - file-uri-to-path: 1.0.0 - bl@4.1.0: dependencies: buffer: 5.7.1 @@ -20175,7 +20216,7 @@ snapshots: '@typescript-eslint/parser': 5.62.0(eslint@8.57.1)(typescript@5.8.2) eslint: 8.57.1 eslint-import-resolver-node: 0.3.9 - eslint-import-resolver-typescript: 3.10.0(eslint-plugin-import@2.31.0(@typescript-eslint/parser@5.62.0(eslint@8.57.1)(typescript@5.8.2))(eslint@8.57.1))(eslint@8.57.1) + eslint-import-resolver-typescript: 3.10.0(eslint-plugin-import@2.31.0)(eslint@8.57.1) eslint-plugin-import: 2.31.0(@typescript-eslint/parser@5.62.0(eslint@8.57.1)(typescript@5.8.2))(eslint-import-resolver-typescript@3.10.0)(eslint@8.57.1) eslint-plugin-jsx-a11y: 6.10.2(eslint@8.57.1) eslint-plugin-react: 7.37.4(eslint@8.57.1) @@ -20222,7 +20263,7 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-import-resolver-typescript@3.10.0(eslint-plugin-import@2.31.0(@typescript-eslint/parser@5.62.0(eslint@8.57.1)(typescript@5.8.2))(eslint@8.57.1))(eslint@8.57.1): + eslint-import-resolver-typescript@3.10.0(eslint-plugin-import@2.31.0)(eslint@8.57.1): dependencies: '@nolyfill/is-core-module': 1.0.39 debug: 4.4.0 @@ -20237,14 +20278,14 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-module-utils@2.12.0(@typescript-eslint/parser@5.62.0(eslint@8.57.1)(typescript@5.8.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.0(eslint-plugin-import@2.31.0(@typescript-eslint/parser@5.62.0(eslint@8.57.1)(typescript@5.8.2))(eslint@8.57.1))(eslint@8.57.1))(eslint@8.57.1): + eslint-module-utils@2.12.0(@typescript-eslint/parser@5.62.0(eslint@8.57.1)(typescript@5.8.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.0)(eslint@8.57.1): dependencies: debug: 3.2.7 optionalDependencies: '@typescript-eslint/parser': 5.62.0(eslint@8.57.1)(typescript@5.8.2) eslint: 8.57.1 eslint-import-resolver-node: 0.3.9 - eslint-import-resolver-typescript: 3.10.0(eslint-plugin-import@2.31.0(@typescript-eslint/parser@5.62.0(eslint@8.57.1)(typescript@5.8.2))(eslint@8.57.1))(eslint@8.57.1) + eslint-import-resolver-typescript: 3.10.0(eslint-plugin-import@2.31.0)(eslint@8.57.1) transitivePeerDependencies: - supports-color @@ -20267,7 +20308,7 @@ snapshots: doctrine: 2.1.0 eslint: 8.57.1 eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.12.0(@typescript-eslint/parser@5.62.0(eslint@8.57.1)(typescript@5.8.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.0(eslint-plugin-import@2.31.0(@typescript-eslint/parser@5.62.0(eslint@8.57.1)(typescript@5.8.2))(eslint@8.57.1))(eslint@8.57.1))(eslint@8.57.1) + eslint-module-utils: 2.12.0(@typescript-eslint/parser@5.62.0(eslint@8.57.1)(typescript@5.8.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.0)(eslint@8.57.1) hasown: 2.0.2 is-core-module: 2.16.1 is-glob: 4.0.3 @@ -20568,8 +20609,6 @@ snapshots: dependencies: flat-cache: 3.2.0 - file-uri-to-path@1.0.0: {} - filelist@1.0.4: dependencies: minimatch: 5.1.6 @@ -22946,6 +22985,8 @@ snapshots: define-properties: 1.2.1 es-object-atoms: 1.1.1 + obuf@1.1.2: {} + on-headers@1.0.2: {} once@1.4.0: @@ -23161,9 +23202,20 @@ snapshots: estree-walker: 3.0.3 is-reference: 3.0.3 + pg-cloudflare@1.2.5: + optional: true + + pg-connection-string@2.8.5: {} + pg-int8@1.0.1: {} - pg-protocol@1.8.0: {} + pg-numeric@1.0.2: {} + + pg-pool@3.9.5(pg@8.15.5): + dependencies: + pg: 8.15.5 + + pg-protocol@1.9.5: {} pg-types@2.2.0: dependencies: @@ -23173,6 +23225,30 @@ snapshots: postgres-date: 1.0.7 postgres-interval: 1.2.0 + pg-types@4.0.2: + dependencies: + pg-int8: 1.0.1 + pg-numeric: 1.0.2 + postgres-array: 3.0.4 + postgres-bytea: 3.0.0 + postgres-date: 2.1.0 + postgres-interval: 3.0.0 + postgres-range: 1.1.4 + + pg@8.15.5: + dependencies: + pg-connection-string: 2.8.5 + pg-pool: 3.9.5(pg@8.15.5) + pg-protocol: 1.9.5 + pg-types: 2.2.0 + pgpass: 1.0.5 + optionalDependencies: + pg-cloudflare: 1.2.5 + + pgpass@1.0.5: + dependencies: + split2: 4.2.0 + picocolors@1.1.1: {} picomatch@2.3.1: {} @@ -23246,14 +23322,26 @@ snapshots: postgres-array@2.0.0: {} + postgres-array@3.0.4: {} + postgres-bytea@1.0.0: {} + postgres-bytea@3.0.0: + dependencies: + obuf: 1.1.2 + postgres-date@1.0.7: {} + postgres-date@2.1.0: {} + postgres-interval@1.2.0: dependencies: xtend: 4.0.2 + postgres-interval@3.0.0: {} + + postgres-range@1.1.4: {} + preact-render-to-string@5.2.3(preact@10.11.3): dependencies: preact: 10.11.3 @@ -24323,6 +24411,8 @@ snapshots: space-separated-tokens@2.0.2: {} + split2@4.2.0: {} + sprintf-js@1.0.3: {} ssim.js@3.5.0: {} From 81ea38783db016c946110b6284472611b77434df Mon Sep 17 00:00:00 2001 From: Nick the Sick Date: Fri, 25 Apr 2025 15:55:26 +0200 Subject: [PATCH 07/16] chore: update env file --- docs/.env.local.example | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/.env.local.example b/docs/.env.local.example index 0b6aca8e63..5d23a84dc1 100644 --- a/docs/.env.local.example +++ b/docs/.env.local.example @@ -5,7 +5,7 @@ AUTH_GITHUB_SECRET= # It's used for authentication when uploading source maps. SENTRY_AUTH_TOKEN= -#Email +# Email SMTP_HOST= SMTP_USER= SMTP_PASS= @@ -21,3 +21,5 @@ POSTGRES_URL= # Polar POLAR_ACCESS_TOKEN= POLAR_WEBHOOK_SECRET= +# Polar Sandbox is used in dev mode: https://sandbox.polar.sh/ +# You may need to delete your user in their dashboard if you get a "cannot attach new external ID error" From 14180f0ac67d94a89df326d6f3e014b36c42d21f Mon Sep 17 00:00:00 2001 From: Nick the Sick Date: Fri, 25 Apr 2025 16:09:30 +0200 Subject: [PATCH 08/16] fix: auto-sign in after email verification --- docs/auth.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/auth.ts b/docs/auth.ts index f98cd1311e..440ad3fc92 100644 --- a/docs/auth.ts +++ b/docs/auth.ts @@ -39,6 +39,7 @@ export const auth = betterAuth({ emailAndPassword: { enabled: true, requireEmailVerification: true, + autoSignIn: true, async sendResetPassword(data) { await sendEmail({ to: data.user.email, From 40dee604ee389bda927124b64525103d3ee7a010 Mon Sep 17 00:00:00 2001 From: Nick the Sick Date: Fri, 25 Apr 2025 16:28:32 +0200 Subject: [PATCH 09/16] fix: make it more sensible --- docs/app/signup/page.tsx | 12 +++++++++++- docs/theme.config.tsx | 14 +++++++++----- 2 files changed, 20 insertions(+), 6 deletions(-) diff --git a/docs/app/signup/page.tsx b/docs/app/signup/page.tsx index 66f741e183..3334f997e2 100644 --- a/docs/app/signup/page.tsx +++ b/docs/app/signup/page.tsx @@ -17,6 +17,13 @@ export default function Register() { }); }; + const handleSignIn = async () => { + await signIn.email({ + email, + password, + }); + }; + return (
Register + {" "} + via GitHub +

+ )} */} +
+ + )} + + ); +} diff --git a/fumadocs/components/styles.css b/fumadocs/components/styles.css new file mode 100644 index 0000000000..af50a5529f --- /dev/null +++ b/fumadocs/components/styles.css @@ -0,0 +1,28 @@ +:focus-visible { + box-shadow: unset !important; +} + +.demo .bn-container:not(.bn-comment-editor), +.demo .bn-editor { + height: 100%; +} + +.demo .bn-container:not(.bn-comment-editor) .bn-editor { + height: 100%; +} + +.demo .bn-editor { + overflow: auto; + padding-block: 1rem; +} + +.demo-contents a { + color: revert; + text-decoration: revert; +} + +.demo code.bn-inline-content { + font-size: 1em; + line-height: 1.5; + display: block; +} diff --git a/fumadocs/content/docs/advanced/ariakit.mdx b/fumadocs/content/docs/advanced/ariakit.mdx new file mode 100644 index 0000000000..df4430d4c3 --- /dev/null +++ b/fumadocs/content/docs/advanced/ariakit.mdx @@ -0,0 +1,16 @@ +--- +title: BlockNote with Ariakit +description: Ariakit rich text editor with BlockNote +imageTitle: BlockNote with Ariakit +--- + + + + +## Using Ariakit with BlockNote + +[Ariakit](https://ariakit.org/) is an open-source library of unstyled (headless), primitive components with a focus on Accessibility. To use BlockNote with Ariakit, you can import `BlockNoteView` from `@blocknote/ariakit` (instead of from `@blocknote/mantine`). + +You can fully style the components with your own CSS, or import the provided default styles using the CSS file from `@blocknote/ariakit/style.css`. + + diff --git a/fumadocs/content/docs/advanced/code-blocks.mdx b/fumadocs/content/docs/advanced/code-blocks.mdx new file mode 100644 index 0000000000..53b9d91fa4 --- /dev/null +++ b/fumadocs/content/docs/advanced/code-blocks.mdx @@ -0,0 +1,88 @@ +--- +title: Code Block Syntax Highlighting +description: This section explains how to add syntax highlighting to code blocks. +imageTitle: Code Block Syntax Highlighting +--- + + + +# Code Block Syntax Highlighting + +To enable code block syntax highlighting, you can use the `codeBlock` option in the `useCreateBlockNote` hook. This is excluded by default to reduce bundle size. + +We've created a default setup which automatically includes some of the most common languages in the most optimized way possible. The language syntaxes are loaded on-demand to ensure the smallest bundle size for your users. + +To use it, you can do the following: + +```sh +npm install @blocknote/code-block +``` + +And then you can use it like this: + +```tsx +import { codeBlock } from "@blocknote/code-block"; + +export default function App() { + // Creates a new editor instance. + const editor = useCreateBlockNote({ + codeBlock, + }); + + // Renders the editor instance using a React component. + return ; +} +``` + +See the code block example for a more detailed example. + + + +## Custom Themes & Languages + +To configure a code block highlighting theme and language, you can use the `codeBlock` option in the `useCreateBlockNote` hook. + +This allows you to configure a [shiki](https://shiki.style) highlighter for the code blocks of your editor, allowing you to tailor the themes and languages you would like to use. + +To create a syntax highlighter, you can use the [shiki-codegen](https://shiki.style/packages/codegen) CLI for generating the code to create a syntax highlighter for your languages and themes. + +For example to create a syntax highlighter using the optimized javascript engine, javascript, typescript, vue, with light and dark themes, you can run the following command: + +```bash +npx shiki-codegen --langs javascript,typescript,vue --themes light,dark --engine javascript --precompiled ./shiki.bundle.ts +``` + +This will generate a `shiki.bundle.ts` file that you can use to create a syntax highlighter for your editor. + +Like this: + +```ts +import { createHighlighter } from "./shiki.bundle.js"; + +export default function App() { + // Creates a new editor instance. + const editor = useCreateBlockNote({ + codeBlock: { + indentLineWithTab: true, + defaultLanguage: "typescript", + supportedLanguages: { + typescript: { + name: "TypeScript", + aliases: ["ts"], + }, + }, + createHighlighter: () => + createHighlighter({ + themes: ["light-plus", "dark-plus"], + langs: [], + }), + }, + }); + + return ; +} +``` + +See the custom code block example for a more detailed example. + + diff --git a/fumadocs/content/docs/advanced/grid-suggestion-menus.mdx b/fumadocs/content/docs/advanced/grid-suggestion-menus.mdx new file mode 100644 index 0000000000..800315a83c --- /dev/null +++ b/fumadocs/content/docs/advanced/grid-suggestion-menus.mdx @@ -0,0 +1,51 @@ +--- +title: Grid Suggestion Menus +description: In addition to displaying Suggestion Menus as stacks, BlockNote also supports displaying them as grids. +imageTitle: Grid Suggestion Menus +--- + +# Grid Suggestion Menus + +Grid Suggestion Menus appear when the user enters a trigger character, and text after the character is used to filter the menu items. + +Grid Suggestion Menus are similar to regular Suggestion Menus, but results are organized in a grid, and users can use all arrow keys (including left, right) on their keyboard to navigate the results. + +## Emoji Picker + +The Emoji Picker is a Grid Suggestion Menu that opens with the `:` character (or when selecting emoji item in the Slash Menu). + +It only displays once the user types 2 non-whitespace characters a query, to minimize cases where the user only wants to enter the `:` character. + + + +### Changing Emoji Picker Columns + +By default, the Emoji Picker is rendered with 10 columns, but you can change this to any amount. In the demo below, the Emoji Picker is changed to only display 5 columns. + + + +Passing `emojiPicker={false}` to `BlockNoteView` tells BlockNote not to show the default Emoji Picker. Adding the `GridSuggestionMenuController` with `triggerCharacter={":"}` and `columns={5}` tells BlockNote to show one with 5 columns instead. + +### Replacing the Emoji Picker Component + +You can replace the React component used for the Emoji Picker with your own, as you can see in the demo below. + + + +Again, we add a `GridSuggestionMenuController` component with `triggerCharacter={":"}` and set `emojiPicker={false}` to replace the default Emoji Picker. + +Now, we also pass a component to its `gridSuggestionMenuComponent` prop. The `gridSuggestionMenuComponent` we pass is responsible for rendering the filtered items. The `GridSuggestionMenuController` controls its position and visibility (below the trigger character), and it also determines which items should be shown. Since we don't specify which items to show (the `getItems` prop isn't defined), it will use the default items for a grid, which are the emojis. + +## Creating additional Grid Suggestion Menus + +You can add additional Grid Suggestion Menus to the editor, which can use any trigger character. The demo below adds an example Grid Suggestion Menu for mentions, where each item is the first character of the user's name, and opens with the `@` character. + + + +Changing the column count in the new Grid Suggestion Menu, or the component used to render it, is done the same way as for the [Emoji Picker](/docs/advanced/grid-suggestion-menus#emoji-picker). For more information about how the mentions elements work, see [Custom Inline Content](/docs/custom-schemas/custom-inline-content). diff --git a/fumadocs/content/docs/advanced/meta.json b/fumadocs/content/docs/advanced/meta.json new file mode 100644 index 0000000000..fd81d02bb4 --- /dev/null +++ b/fumadocs/content/docs/advanced/meta.json @@ -0,0 +1,15 @@ +{ + "title": "Advanced", + "pages": [ + "nextjs", + "ariakit", + "shadcn", + "grid-suggestion-menus", + "code-blocks", + "paste-handling", + "tables", + "custom-schemas", + "vanilla-js", + "..." + ] +} diff --git a/fumadocs/content/docs/advanced/nextjs.mdx b/fumadocs/content/docs/advanced/nextjs.mdx new file mode 100644 index 0000000000..361daad076 --- /dev/null +++ b/fumadocs/content/docs/advanced/nextjs.mdx @@ -0,0 +1,72 @@ +--- +title: Next.js and BlockNote +description: Details on integrating BlockNote with Next.js +imageTitle: Next.js and BlockNote +--- + +# Next.js and BlockNote + +BlockNote is a component that should only be rendered client-side (and not on the server). If you're using Next.js, you need to make sure that Next.js does not try to render BlockNote as a server-side component. + +Make sure to use BlockNote in a [Client Component](https://nextjs.org/docs/getting-started/react-essentials#client-components). You can do this by creating a separate file for your component (**make sure this sits outside of your `pages` or `app` directory, for example `components/Editor.tsx`**), and starting that with `"use client";` [directive](https://react.dev/reference/react/use-client): + +```typescript jsx +"use client"; // this registers as a Client Component +import "@blocknote/core/fonts/inter.css"; +import { useCreateBlockNote } from "@blocknote/react"; +import { BlockNoteView } from "@blocknote/mantine"; +import "@blocknote/mantine/style.css"; + +// Our component we can reuse later +export default function Editor() { + // Creates a new editor instance. + const editor = useCreateBlockNote(); + + // Renders the editor instance using a React component. + return ; +} +``` + +## Import as dynamic + +In the same directory, create a new file called `DynamicEditor.tsx`: +Here, we will use [Dynamic Imports](https://nextjs.org/docs/pages/building-your-application/optimizing/lazy-loading) to make sure BlockNote is only imported on the client-side. + +You can import the component we just created above using `next/dynamic` in your page: + +```typescript jsx +"use client"; + +import dynamic from "next/dynamic"; + +export const Editor = dynamic(() => import("./Editor"), { ssr: false }); +``` + +## Import in a page / app + +Now, you can import the dynamic editor in your page or app: + +```typescript jsx +import { Editor } from "../components/DynamicEditor"; + + +function App() { + return ( +
+ +
+ ); +} +``` + +## React 19 / Next 15 StrictMode + +BlockNote is not yet compatible with React 19 / Next 15 StrictMode. For now, disable StrictMode in your `next.config.ts`: + +```typescript +... +reactStrictMode: false, +... +``` + +This should resolve any issues you might run into when embedding BlockNote in your Next.js React app! diff --git a/fumadocs/content/docs/advanced/paste-handling.mdx b/fumadocs/content/docs/advanced/paste-handling.mdx new file mode 100644 index 0000000000..0b428c1a6d --- /dev/null +++ b/fumadocs/content/docs/advanced/paste-handling.mdx @@ -0,0 +1,74 @@ +--- +title: Paste Handling +description: This section explains how to handle paste events in BlockNote. +imageTitle: Paste Handling +--- + + + +# Paste Handling + +BlockNote, by default, attempts to paste content in the following order: + +- VS Code compatible content +- Files +- BlockNote HTML +- Markdown +- HTML +- Plain text + +> In certain cases, BlockNote will attempt to detect markdown in the clipboard and paste that into the editor as rich text. + +You can change the default paste behavior by providing a custom paste handler, which will give you full control over how pasted content is inserted into the editor. + +## `pasteHandler` option + +The `pasteHandler` option is a function that receives the following arguments: + +```ts +type PasteHandler = (context: { + event: ClipboardEvent; + editor: BlockNoteEditor; + defaultPasteHandler: (context?: { + prioritizeMarkdownOverHTML?: boolean; + plainTextAsMarkdown?: boolean; + }) => boolean; +}) => boolean; +``` + +- `event`: The paste event. +- `editor`: The current editor instance. +- `defaultPasteHandler`: The default paste handler. If you only need to customize the paste behavior a little bit, you can fall back on the default paste handler. + +The `defaultPasteHandler` function can be called with the following options: + +- `prioritizeMarkdownOverHTML`: Whether to prioritize Markdown content in `text/plain` over `text/html` when pasting from the clipboard. +- `plainTextAsMarkdown`: Whether to interpret plain text as markdown and paste that as rich text or to paste the text directly into the editor. + + +## Custom Paste Handler + +You can also provide your own paste handler by providing a function to the `pasteHandler` option. + +In this example, we handle the paste event if the clipboard data contains `text/my-custom-format`. If we don't handle the paste event, we call the default paste handler to do the default behavior. + +```ts +const editor = new BlockNoteEditor({ + pasteHandler: ({ event, editor, defaultPasteHandler }) => { + if (event.clipboardData?.types.includes("text/my-custom-format")) { + // You can do any custom logic here, for example you could transform the clipboard data before pasting it + const markdown = customToMarkdown(event.clipboardData.getData("text/my-custom-format")); + + // The editor is able paste markdown (`pasteMarkdown`), HTML (`pasteHTML`), or plain text (`pasteText`) + editor.pasteMarkdown(markdown); + // We handled the paste event, so return true, returning false will cancel the paste event + return true; + } + + // If we didn't handle the paste event, call the default paste handler to do the default behavior + return defaultPasteHandler(); + }, +}); +``` + +See an example of this in the [Custom Paste Handler](/examples/basic/custom-paste-handler) example. \ No newline at end of file diff --git a/fumadocs/content/docs/advanced/shadcn.mdx b/fumadocs/content/docs/advanced/shadcn.mdx new file mode 100644 index 0000000000..c536bbd196 --- /dev/null +++ b/fumadocs/content/docs/advanced/shadcn.mdx @@ -0,0 +1,52 @@ +--- +title: BlockNote with ShadCN and Tailwind +description: ShadCN + Tailwind rich text editor using BlockNote +imageTitle: BlockNote with ShadCN and Tailwind +--- + + + + +## Using ShadCN, Radix and Tailwind with BlockNote + +[shadcn/ui](https://ui.shadcn.com/) is an open-source collection of React components based on [Radix](https://radix-ui.com/) and Tailwind. To use BlockNote with shadcn, you can import `BlockNoteView` from `@blocknote/shadcn` (instead of from `@blocknote/mantine`) and the stylesheet from `@blocknote/shadcn/style.css`. + + + +## ShadCN Customization + +BlockNote comes with default shadcn components. However, it's likely that you have copied and possibly customized your own shadcn components in your project. +To make BlockNote use the ShadCN components from your project instead of the default ones, you can pass them using the `shadCNComponents` prop of `BlockNoteView`: + +```tsx +import * as Button from "@/components/ui/button" +import * as Select from "@/components/ui/select" + +return ( + +); +``` + +You can pass components from the following ShadCN modules: + +- Badge +- Button +- Card +- DropdownMenu +- Form +- Input +- Label +- Popover +- Select +- Tabs +- Toggle +- Tooltip + + + To ensure compatibility, your ShadCN components should not use Portals + (comment these out from your DropdownMenu, Popover and Select components). + diff --git a/fumadocs/content/docs/advanced/tables.mdx b/fumadocs/content/docs/advanced/tables.mdx new file mode 100644 index 0000000000..2dc4a598dc --- /dev/null +++ b/fumadocs/content/docs/advanced/tables.mdx @@ -0,0 +1,88 @@ +--- +title: Advanced Tables +description: How to use more advanced features of tables. +imageTitle: Advanced Tables +--- + +Tables by default are a simple way to display data in a grid. But, BlockNote also supports more advanced features like: + +- Split cells +- Cell background color +- Cell text color +- Header rows & columns + +To keep the default table experience easy to use, these features are disabled by default. + +You can enable them by passing the `tables` option when creating the editor. + +```ts +const editor = new BlockNoteEditor({ + tables: { + splitCells: true, + cellBackgroundColor: true, + cellTextColor: true, + headers: true, + }, +}); +``` + +You can choose to enable only certain features, or none at all. Giving you the flexibility to use tables how you need in your app. + +Here's an example of the editor with all features enabled: + + + +## Cell background color + +To enable cell background color, you need to pass `cellBackgroundColor: true` to the `tables` option. + +```ts +const editor = new BlockNoteEditor({ + tables: { + cellBackgroundColor: true, + }, +}); +``` + +## Cell text color + +To enable cell text color, you need to pass `cellTextColor: true` to the `tables` option. + +```ts +const editor = new BlockNoteEditor({ + tables: { + cellTextColor: true, + }, +}); +``` + + +## Header rows & columns + +BlockNote supports headers in tables, which are the first row and/or first column of a table. + +To enable it, you need to pass `headers: true` to the `tables` option. + +```ts +const editor = new BlockNoteEditor({ + tables: { + headers: true, + }, +}); +``` + +## Split cells + +Splitting and merging cells is a common feature of more advanced table editors. + +To enable it, you need to pass `splitCells: true` to the `tables` option. + +```ts +const editor = new BlockNoteEditor({ + tables: { + splitCells: true, + }, +}); +``` + + diff --git a/fumadocs/content/docs/advanced/vanilla-js.mdx b/fumadocs/content/docs/advanced/vanilla-js.mdx new file mode 100644 index 0000000000..2bfd47c4fa --- /dev/null +++ b/fumadocs/content/docs/advanced/vanilla-js.mdx @@ -0,0 +1,122 @@ +--- +title: Usage Without React (Vanilla JS) +description: BlockNote is mainly designed as a quick and easy drop-in block-based editor for React apps, but can also be used in vanilla JavaScript apps. +imageTitle: Usage Without React (Vanilla JS) +--- + +# Usage Without React (Vanilla JS) + +BlockNote is mainly designed as a quick and easy drop-in block-based editor for React apps, but can also be used in vanilla JavaScript apps. However, this does involve writing your own UI elements. + + + We recommend using BlockNote with React so you can use the built-in UI + components. This document will explain how you can use BlockNote without + React, and write your own components, but this is not recommended as you'll + lose the great out-of-the-box experience that BlockNote offers. + + +## Installing with NPM + +To install only the vanilla JS parts of BlockNote with [NPM](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm), run: + +```console +npm install @blocknote/core +``` + +## Creating an editor + +This is how to create a new BlockNote editor: + +```typescript +import { BlockNoteEditor } from "@blocknote/core"; + +const editor = BlockNoteEditor.create(); + +editor.mount(document.getElementById("root")); // element to append the editor to +``` + +Now, you'll have a plain BlockNote instance on your page. However, it's missing some menus and other UI elements. + +## Creating your own UI elements + +Because you can't use the built-in React [UI Components](/docs/quickstart), you'll need to create and register your own UI elements. + +While it's up to you to decide how you want the elements to be rendered, BlockNote provides methods for updating the visibility, position, and state of your elements: + +```typescript +type UIElement = + | "formattingToolbar" + | "linkToolbar" + | "filePanel" + | "sideMenu" + | "suggestionMenu" + | "tableHandles" + +const uiElement: UIElement = ...; + +editor[uiElement].onUpdate((uiElementState: ...) => { + ...; +}) +``` + +Let's look at how you could add the [Side Menu]() to your editor: + +```typescript +import { BlockNoteEditor } from "@blocknote/core"; + +const editor = BlockNoteEditor.create({ + element: document.getElementById("root")!, +}); + +export function createButton(text: string, onClick?: () => void) { + const element = document.createElement("a"); + element.href = "#"; + element.text = text; + element.style.margin = "10px"; + + if (onClick) { + element.addEventListener("click", (e) => { + onClick(); + e.preventDefault(); + }); + } + + return element; +} + +let element: HTMLElement; + +editor.sideMenu.onUpdate((sideMenuState) => { + if (!element) { + element = document.createElement("div"); + element.style.background = "gray"; + element.style.position = "absolute"; + element.style.padding = "10px"; + element.style.opacity = "0.8"; + const addBtn = createButton("+", () => { + editor.sideMenu.addBlock(); + }); + element.appendChild(addBtn); + + const dragBtn = createButton("::", () => {}); + + dragBtn.addEventListener("dragstart", editor.sideMenu.blockDragStart); + dragBtn.addEventListener("dragend", editor.sideMenu.blockDragEnd); + dragBtn.draggable = true; + element.style.display = "none"; + element.appendChild(dragBtn); + + document.getElementById("root")!.appendChild(element); + } + + if (sideMenuState.show) { + element.style.display = "block"; + + element.style.top = sideMenuState.referencePos.top + "px"; + element.style.left = + sideMenuState.referencePos.x - element.offsetWidth + "px"; + } else { + element.style.display = "none"; + } +}); +``` diff --git a/fumadocs/content/docs/collaboration/comments.mdx b/fumadocs/content/docs/collaboration/comments.mdx new file mode 100644 index 0000000000..803611e3df --- /dev/null +++ b/fumadocs/content/docs/collaboration/comments.mdx @@ -0,0 +1,162 @@ +--- +title: Comments +description: Learn how to enable comments in your BlockNote editor +imageTitle: Comments +--- + +import {Example} from "@/components/example"; + +# Comments + +BlockNote supports Comments, Comment Threads (replies) and emoji reactions out of the box. + +To enable comments in your editor, you need to: + +- provide a `resolveUsers` so BlockNote can retrieve and display user information (names and avatars). +- provide a `ThreadStore` so BlockNote can store and retrieve comment threads. +- enable real-time collaboration (see [Real-time collaboration](/docs/collaboration/real-time-collaboration)) + +```tsx +const editor = useCreateBlockNote({ + resolveUsers: async (userIds: string[]) => { + // return user information for the given userIds (see below) + }, + comments: { + threadStore: yourThreadStore, // see below + }, + // ... + collaboration: { + // ... // see real-time collaboration docs + }, +}); +``` + +**Demo** + + + +## ThreadStores + +A ThreadStore is used to store and retrieve comment threads. BlockNote is backend agnostic, so you can use any database or backend to store the threads. +BlockNote comes with several built-in ThreadStore implementations: + +### `YjsThreadStore` + +The `YjsThreadStore` provides direct Yjs-based storage for comments, storing thread data directly in the Yjs document. This implementation is ideal for simple collaborative setups where all users have write access to the document. + +```tsx +import { YjsThreadStore } from "@blocknote/core/comments"; + +const threadStore = new YjsThreadStore( + userId, // The active user's ID + yDoc.getMap("threads"), // Y.Map to store threads + new DefaultThreadStoreAuth(userId, "editor"), // Authorization information, see below +); +``` + +_Note: While this is the easiest to implement, it requires users to have write access to the Yjs document to leave comments. Also, without proper server-side validation, any user could technically modify other users' comments._ + +### `RESTYjsThreadStore` + +The `RESTYjsThreadStore` combines Yjs storage with a REST API backend, providing secure comment management while maintaining real-time collaboration. This implementation is ideal when you have strong authentication requirements, but is a little more work to set up. + +In this implementation, data is written to the Yjs document via a REST API which can handle access control. Data is still retrieved from the Yjs document directly (after it's been updated by the REST API), this way all comment information automatically syncs between clients using the existing collaboration provider. + +```tsx +import { + RESTYjsThreadStore, + DefaultThreadStoreAuth, +} from "@blocknote/core/comments"; + +const threadStore = new RESTYjsThreadStore( + "https://api.example.com/comments", // Base URL for the REST API + { + Authorization: "Bearer your-token", // Optional headers to add to requests + }, + yDoc.getMap("threads"), // Y.Map to retrieve commend data from + new DefaultThreadStoreAuth(userId, "editor"), // Authorization rules (see below) +); +``` + +An example implementation of the REST API can be found in the [example repository](https://github.com/TypeCellOS/BlockNote-demo-nextjs-hocuspocus). + +_Note: Because writes are executed via a REST API, the `RESTYjsThreadStore` is not suitable for local-first applications that should be able to add and edit comments offline._ + +### `TiptapThreadStore` + +The `TiptapThreadStore` integrates with Tiptap's collaboration provider for comment management. This implementation is designed specifically for use with Tiptap's collaborative editing features. + +```tsx +import { + TiptapThreadStore, + DefaultThreadStoreAuth, +} from "@blocknote/core/comments"; +import { TiptapCollabProvider } from "@hocuspocus/provider"; + +// Create a TiptapCollabProvider (you probably have this already) +const provider = new TiptapCollabProvider({ + name: "test", + baseUrl: "https://collab.yourdomain.com", + appId: "test", + document: doc, +}); + +// Create a TiptapThreadStore +const threadStore = new TiptapThreadStore( + userId, // The active user's ID + provider, // Tiptap collaboration provider + new DefaultThreadStoreAuth(userId, "editor"), // Authorization rules (see below) +); +``` + +### ThreadStoreAuth + +The `ThreadStoreAuth` class defines the authorization rules for interacting with comments. Every ThreadStore implementation requires a `ThreadStoreAuth` instance. BlockNote uses the `ThreadStoreAuth` instance to deterine which interactions are allowed for the current user (for example, whether they can create a new comment, edit or delete a comment, etc.). + +The `DefaultThreadStoreAuth` class provides a basic implementation of the `ThreadStoreAuth` class. It takes a user ID and a role ("comment" or "editor") and implements the rules. See the [source code](https://github.com/TypeCellOS/BlockNote/blob/main/packages/core/src/comments/threadstore/DefaultThreadStoreAuth.ts) for more details. + +_Note: The `ThreadStoreAuth` only used to show / hide options in the UI. To secure comment related data, you still need to implement your own server-side validation (e.g. using `RESTYjsThreadStore` and a secure REST API)._ + +## `resolveUsers` function + +When a user interacts with a comment, the data is stored in the ThreadStore, along with the active user ID (as specified when initiating the ThreadStore). + +To display comments, BlockNote needs to retrieve user information (such as the username and avatar) based on the user ID. To do this, you need to provide a `resolveUsers` function in the editor options. + +This function is called with an array of user IDs, and should return an array of `User` objects in the same order. + +```tsx +type User = { + id: string; + username: string; + avatarUrl: string; +}; + +async function myResolveUsers(userIds: string[]): Promise { + // fetch user information from your database / backend + // and return an array of User objects + + return await callYourBackend(userIds); + + // Return a list of users + return users; +} +``` + +## Sidebar View + +BlockNote also offers a different way of viewing and interacting with comments, via a sidebar instead of floating in the editor, using the `ThreadsSidebar` component: + + + +The only requirement for `ThreadsSidebar` is that it should be placed somewhere within your `BlockNoteView`, other than that you can position and style it however you want. + +`ThreadsSidebar` also takes 2 props: + +**`filter`**: Filter the comments in the sidebar. Can pass `"open"`, `"resolved"`, or `"all"`, to only show open, resolved, or all comments. Defaults to `"all"`. + +**`sort`**: Sort the comments in the sidebar. Can pass `"position"`, `"recent-activity"`, or `"oldest"`. Sorting by `"recent-activity"` uses the most recently added comment to sort threads, while `"oldest"` uses the thread creation date. Sorting by `"position"` puts comments in the same order as their reference text in the editor. Defaults to `"position"`. + +**`maxCommentsBeforeCollapse`**: The maximum number of comments that can be in a thread before the replies get collapsed. Defaults to 5. + +See [here](https://playground.blocknotejs.org/collaboration/comments-with-sidebar?hideMenu=true) for a standalone example of the `ThreadsSidebar` component. diff --git a/fumadocs/content/docs/collaboration/index.mdx b/fumadocs/content/docs/collaboration/index.mdx new file mode 100644 index 0000000000..a10e7d34e2 --- /dev/null +++ b/fumadocs/content/docs/collaboration/index.mdx @@ -0,0 +1,8 @@ +--- +title: Collaboration +description: Learn how to create multiplayer experiences with BlockNote +--- + +BlockNote supports multi-user collaborative document editing. + + diff --git a/fumadocs/content/docs/collaboration/meta.json b/fumadocs/content/docs/collaboration/meta.json new file mode 100644 index 0000000000..ed0a0329eb --- /dev/null +++ b/fumadocs/content/docs/collaboration/meta.json @@ -0,0 +1,4 @@ +{ + "title": "Collaboration", + "pages": ["real-time-collaboration", "comments"] +} diff --git a/fumadocs/content/docs/collaboration/real-time-collaboration.mdx b/fumadocs/content/docs/collaboration/real-time-collaboration.mdx new file mode 100644 index 0000000000..9e3e1ff696 --- /dev/null +++ b/fumadocs/content/docs/collaboration/real-time-collaboration.mdx @@ -0,0 +1,191 @@ +--- +title: Real-time Collaboration +description: Let's see how you can add Multiplayer capabilities to your BlockNote setup, and allow real-time collaboration between users (similar to Google Docs) +imageTitle: Real-time Collaboration +--- + + + +# Real-time Collaboration (multiplayer text editor) + +Let's see how you can add Multiplayer capabilities to your BlockNote setup, and allow real-time collaboration between users (similar to Google Docs): + + + +_Try the live demo on the [homepage](https://www.blocknotejs.org)_ + +BlockNote uses [Yjs](https://github.com/yjs/yjs) for this, and you can set it up with the `collaboration` option: + +```typescript +import * as Y from "yjs"; +import { WebrtcProvider } from "y-webrtc"; +// ... + +const doc = new Y.Doc(); + +const provider = new WebrtcProvider("my-document-id", doc); // setup a yjs provider (explained below) +const editor = useCreateBlockNote({ + // ... + collaboration: { + // The Yjs Provider responsible for transporting updates: + provider, + // Where to store BlockNote data in the Y.Doc: + fragment: doc.getXmlFragment("document-store"), + // Information (name and color) for this user: + user: { + name: "My Username", + color: "#ff0000", + }, + // When to show user labels on the collaboration cursor. Set by default to + // "activity" (show when the cursor moves), but can also be set to "always". + showCursorLabels: "activity" + }, + // ... +}); +``` + +## Yjs Providers + +When a user edits the document, an incremental change (or "update") is captured and can be shared between users of your app. You can share these updates by setting up a _Yjs Provider_. In the snipped above, we use [y-webrtc](https://github.com/yjs/y-webrtc) which shares updates over WebRTC (and BroadcastChannel), but you might be interested in different providers for production-ready use cases. + +- [Liveblocks](https://liveblocks.io/yjs) A fully hosted WebSocket infrastructure and persisted data store for Yjs documents. Includes webhooks, REST API, and browser DevTools, all for Yjs +- [PartyKit](https://www.partykit.io/) A serverless provider that runs on Cloudflare +- [Y-Sweet](https://jamsocket.com/y-sweet) An open-source provider that runs fully managed on [Jamsocket](https://jamsocket.com) or self-hosted in your own cloud +- [Hocuspocus](https://www.hocuspocus.dev/) open source and extensible Node.js server with pluggable storage (scales with Redis) +- [y-websocket](https://github.com/yjs/y-websocket) provider that you can connect to your own websocket server +- [y-indexeddb](https://github.com/yjs/y-indexeddb) for offline storage +- [y-webrtc](https://github.com/yjs/y-webrtc) transmits updates over WebRTC +- [Matrix-CRDT](https://github.com/yousefED/matrix-crdt) syncs updates over Matrix (experimental) +- [Nostr-CRDT](https://github.com/yousefED/nostr-crdt) syncs updates over Nostr (experimental) + +## Liveblocks + +Liveblocks provides a hosted back-end for Yjs. You can create a fully-featured example project which uses Liveblocks with BlockNote by running the command below (you will need a Liveblocks account for this): + +```shell +npx create-liveblocks-app@latest --example nextjs-blocknote --api-key +``` + +