diff --git a/apps/web/app/components/SoapNoteDisplay.tsx b/apps/web/components/SoapNoteDisplay.tsx
similarity index 100%
rename from apps/web/app/components/SoapNoteDisplay.tsx
rename to apps/web/components/SoapNoteDisplay.tsx
diff --git a/apps/web/app/components/SoapNoteEditor.tsx b/apps/web/components/SoapNoteEditor.tsx
similarity index 100%
rename from apps/web/app/components/SoapNoteEditor.tsx
rename to apps/web/components/SoapNoteEditor.tsx
diff --git a/apps/web/middleware.ts b/apps/web/middleware.ts
index e875974..98f1b1e 100644
--- a/apps/web/middleware.ts
+++ b/apps/web/middleware.ts
@@ -16,12 +16,9 @@ export async function middleware(request: NextRequest) {
secret: process.env.NEXTAUTH_SECRET,
});
- // Unauthenticated visitors at root get redirected to the marketing site
- if (!token && request.nextUrl.pathname === "/") {
- const wwwUrl = process.env.NEXT_PUBLIC_WWW_URL || "https://openvpm.com";
- return NextResponse.redirect(wwwUrl);
- }
-
+ // Unauthenticated visitors go to the demo login, which offers one-click
+ // demo access. (Previously the root path bounced to the marketing site,
+ // which dead-ended anyone who came straight to demo.openvpm.com to try it.)
if (!token) {
const loginUrl = new URL("/login", request.url);
return NextResponse.redirect(loginUrl);
diff --git a/apps/www/app/api/subscribe/route.ts b/apps/www/app/api/subscribe/route.ts
new file mode 100644
index 0000000..ec47eb8
--- /dev/null
+++ b/apps/www/app/api/subscribe/route.ts
@@ -0,0 +1,75 @@
+import { NextResponse } from "next/server";
+
+const EMAIL_REGEX = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
+
+// Content/newsletter subscribe. Captures to Slack today (same channel as the
+// waitlist) so no signup is lost; point this at a real ESP list when one is
+// wired (see the co-founder memo / growth playbook).
+export async function POST(request: Request) {
+ try {
+ const body = await request.json();
+ const email = body.email?.trim();
+ const source = body.source?.trim() || "site";
+
+ if (!email || !EMAIL_REGEX.test(email)) {
+ return NextResponse.json(
+ { error: "Please enter a valid email address." },
+ { status: 400 }
+ );
+ }
+
+ const webhookUrl = process.env.SLACK_WEBHOOK_URL;
+ if (!webhookUrl) {
+ console.error("Missing SLACK_WEBHOOK_URL");
+ return NextResponse.json(
+ { error: "Subscribe is temporarily unavailable." },
+ { status: 503 }
+ );
+ }
+
+ const slackPayload = {
+ text: `New OpenVPM subscriber β ${email}`,
+ blocks: [
+ {
+ type: "header",
+ text: { type: "plain_text", text: "π° New OpenVPM subscriber" },
+ },
+ {
+ type: "section",
+ fields: [
+ { type: "mrkdwn", text: `*Email:*\n${email}` },
+ { type: "mrkdwn", text: `*Source:*\n${source}` },
+ ],
+ },
+ {
+ type: "context",
+ elements: [
+ { type: "mrkdwn", text: `openvpm.com Β· ${new Date().toISOString()}` },
+ ],
+ },
+ ],
+ };
+
+ const res = await fetch(webhookUrl, {
+ method: "POST",
+ headers: { "Content-Type": "application/json" },
+ body: JSON.stringify(slackPayload),
+ });
+
+ if (!res.ok) {
+ console.error("Slack webhook error:", res.status, await res.text());
+ return NextResponse.json(
+ { error: "Something went wrong. Please try again." },
+ { status: 500 }
+ );
+ }
+
+ return NextResponse.json({ success: true });
+ } catch (error) {
+ console.error("Subscribe error:", error);
+ return NextResponse.json(
+ { error: "Something went wrong. Please try again." },
+ { status: 500 }
+ );
+ }
+}
diff --git a/apps/www/app/blog/[slug]/page.tsx b/apps/www/app/blog/[slug]/page.tsx
new file mode 100644
index 0000000..ab0c30f
--- /dev/null
+++ b/apps/www/app/blog/[slug]/page.tsx
@@ -0,0 +1,82 @@
+import type { Metadata } from "next";
+import Link from "next/link";
+import { notFound } from "next/navigation";
+import { ArrowLeft, Github } from "lucide-react";
+import { posts, getPost } from "@/lib/posts";
+import { PostContent } from "@/components/blog/post-content";
+import { SubscribeForm } from "@/components/subscribe-form";
+
+export function generateStaticParams() {
+ return posts.map((p) => ({ slug: p.slug }));
+}
+
+export function generateMetadata({ params }: { params: { slug: string } }): Metadata {
+ const post = getPost(params.slug);
+ if (!post) return { title: "Not found" };
+ return {
+ title: post.title,
+ description: post.excerpt,
+ openGraph: { title: post.title, description: post.excerpt, type: "article" },
+ };
+}
+
+export default function PostPage({ params }: { params: { slug: string } }) {
+ const post = getPost(params.slug);
+ if (!post) notFound();
+
+ return (
+
+
+
+
+ All writing
+
+
+
+ {post.date}
+ Β·
+ {post.author}
+ Β·
+ {post.readingMinutes} min read
+
+
+ {post.title}
+
+
+
+
+ {/* Conversion: every post ends with a way to engage. */}
+
+
+ We're building this in the open
+
+
+ OpenVPM is free and MIT licensed. Try the live demo, star the repo, or
+ subscribe and tell us where we're wrong β the harder the feedback, the better.
+
+
+
+
+
+
+ );
+}
diff --git a/apps/www/app/blog/page.tsx b/apps/www/app/blog/page.tsx
new file mode 100644
index 0000000..f81d9c8
--- /dev/null
+++ b/apps/www/app/blog/page.tsx
@@ -0,0 +1,71 @@
+import type { Metadata } from "next";
+import Link from "next/link";
+import { ArrowRight } from "lucide-react";
+import { posts } from "@/lib/posts";
+import { SubscribeForm } from "@/components/subscribe-form";
+
+export const metadata: Metadata = {
+ title: "Writing",
+ description:
+ "Notes on building open, API-first veterinary software β owning your data, open APIs, and AI agents in the clinic.",
+};
+
+export default function BlogIndexPage() {
+ return (
+
+
+
+
+ Writing
+
+
+ Notes on building veterinary software in the open β owning your data,
+ open APIs, and putting AI agents to work in the clinic. We publish our
+ thinking here and we want yours back.
+
+
+
+
+ {posts.map((post) => (
+
+
+ {post.date}
+ Β·
+ {post.readingMinutes} min read
+
+
+
+ {post.title}
+
+
+ {post.excerpt}
+
+ Read
+
+
+
+ ))}
+
+
+
+
+ Get new writing by email
+
+
+ No spam β just our notes on open veterinary software as we publish them.
+ Reply with your thoughts; we read every one.
+
+
+
+
+
+
+
+ );
+}
diff --git a/apps/www/app/sitemap.ts b/apps/www/app/sitemap.ts
index 3c4621e..4b7d4c1 100644
--- a/apps/www/app/sitemap.ts
+++ b/apps/www/app/sitemap.ts
@@ -1,4 +1,5 @@
import type { MetadataRoute } from "next";
+import { posts } from "@/lib/posts";
const baseUrl = "https://openvpm.com";
@@ -10,5 +11,12 @@ export default function sitemap(): MetadataRoute.Sitemap {
{ url: `${baseUrl}/why`, lastModified: now, changeFrequency: "monthly", priority: 0.7 },
{ url: `${baseUrl}/install`, lastModified: now, changeFrequency: "weekly", priority: 0.9 },
{ url: `${baseUrl}/updates`, lastModified: now, changeFrequency: "weekly", priority: 0.6 },
+ { url: `${baseUrl}/blog`, lastModified: now, changeFrequency: "weekly", priority: 0.7 },
+ ...posts.map((p) => ({
+ url: `${baseUrl}/blog/${p.slug}`,
+ lastModified: now,
+ changeFrequency: "monthly" as const,
+ priority: 0.6,
+ })),
];
}
diff --git a/apps/www/components/blog/post-content.tsx b/apps/www/components/blog/post-content.tsx
new file mode 100644
index 0000000..f327abb
--- /dev/null
+++ b/apps/www/components/blog/post-content.tsx
@@ -0,0 +1,47 @@
+import type { Block } from "@/lib/posts";
+
+export function PostContent({ blocks }: { blocks: Block[] }) {
+ return (
+
+ {blocks.map((block, i) => {
+ switch (block.type) {
+ case "h2":
+ return (
+
+ {block.text}
+
+ );
+ case "quote":
+ return (
+
+ {block.text}
+
+ );
+ case "ul":
+ return (
+
+ {block.items.map((item, j) => (
+
+
+ {item}
+
+ ))}
+
+ );
+ default:
+ return (
+
+ {block.text}
+
+ );
+ }
+ })}
+
+ );
+}
diff --git a/apps/www/components/footer.tsx b/apps/www/components/footer.tsx
index f9b38ac..516b890 100644
--- a/apps/www/components/footer.tsx
+++ b/apps/www/components/footer.tsx
@@ -42,6 +42,9 @@ export function MarketingFooter() {
Why Open Source
+
+ Writing
+
Updates
diff --git a/apps/www/components/nav.tsx b/apps/www/components/nav.tsx
index ac987d6..0946633 100644
--- a/apps/www/components/nav.tsx
+++ b/apps/www/components/nav.tsx
@@ -29,6 +29,7 @@ const navLinks = [
{ label: "Features", href: "/features" },
{ label: "Install", href: "/install" },
{ label: "Why Open Source", href: "/why" },
+ { label: "Writing", href: "/blog" },
{ label: "Updates", href: "/updates" },
];
diff --git a/apps/www/components/subscribe-form.tsx b/apps/www/components/subscribe-form.tsx
new file mode 100644
index 0000000..bc23106
--- /dev/null
+++ b/apps/www/components/subscribe-form.tsx
@@ -0,0 +1,79 @@
+"use client";
+
+import { useState } from "react";
+import { ArrowRight, CheckCircle2, Loader2 } from "lucide-react";
+
+type Step = "idle" | "submitting" | "success" | "error";
+
+export function SubscribeForm({ source }: { source?: string }) {
+ const [step, setStep] = useState("idle");
+ const [email, setEmail] = useState("");
+ const [errorMsg, setErrorMsg] = useState("");
+
+ const handleSubmit = async (e: React.FormEvent) => {
+ e.preventDefault();
+ if (!email.trim()) return;
+ setStep("submitting");
+ setErrorMsg("");
+ try {
+ const res = await fetch("/api/subscribe", {
+ method: "POST",
+ headers: { "Content-Type": "application/json" },
+ body: JSON.stringify({ email: email.trim(), source }),
+ });
+ const data = await res.json();
+ if (!res.ok) {
+ setStep("error");
+ setErrorMsg(data.error || "Something went wrong. Please try again.");
+ return;
+ }
+ setStep("success");
+ } catch {
+ setStep("error");
+ setErrorMsg("Something went wrong. Please try again.");
+ }
+ };
+
+ if (step === "success") {
+ return (
+
+
+ Subscribed β talk soon.
+
+ );
+ }
+
+ return (
+
+ );
+}
diff --git a/apps/www/lib/posts.ts b/apps/www/lib/posts.ts
new file mode 100644
index 0000000..63a4e68
--- /dev/null
+++ b/apps/www/lib/posts.ts
@@ -0,0 +1,99 @@
+/**
+ * Thought-leadership content for the OpenVPM blog. Stored as structured blocks
+ * (zero dependencies, fully type-checked) and rendered by app/blog. Add a post
+ * by appending to `posts` β newest first.
+ */
+
+export type Block =
+ | { type: "p"; text: string }
+ | { type: "h2"; text: string }
+ | { type: "ul"; items: string[] }
+ | { type: "quote"; text: string };
+
+export interface Post {
+ slug: string;
+ title: string;
+ /** Display date, e.g. "June 3, 2026". */
+ date: string;
+ author: string;
+ excerpt: string;
+ readingMinutes: number;
+ content: Block[];
+}
+
+export const posts: Post[] = [
+ {
+ slug: "why-veterinary-software-should-be-open",
+ title: "Why veterinary software should be open",
+ date: "June 3, 2026",
+ author: "Evan Gauer",
+ excerpt:
+ "Every other part of the clinic is built on standards. The software that runs it shouldn't be a locked box you rent forever.",
+ readingMinutes: 4,
+ content: [
+ { type: "p", text: "Walk into any veterinary clinic and almost everything follows a standard. Drugs have monographs. Labs report against reference ranges. Anesthesia has protocols. Then you get to the software that ties it all together β the practice management system β and the standards disappear. Your data lives in a format only the vendor can read. The API, if there is one, is locked behind a partnership team. And the bill arrives every month whether the software got better or not." },
+ { type: "h2", text: "Closed software is a tax on the whole industry" },
+ { type: "p", text: "When the system of record is closed, every good idea downstream gets harder. A reminder tool has to beg for integration access. An AI scribe can read but not write. A new analytics product can't get the data out. The clinic that wants to switch finds out their five years of records are effectively hostage. None of this is about bad people β it's about incentives. A closed PIMS makes more money the harder it is to leave." },
+ { type: "quote", text: "The best software for veterinary medicine should be built with the veterinary community, not sold to it." },
+ { type: "h2", text: "What open changes" },
+ { type: "ul", items: [
+ "Your data is yours. Full export, any time, in a format you can read β no lock-in, no exit fee.",
+ "Anyone can build on it. A documented, read-write API means the next great tool doesn't need anyone's permission.",
+ "The roadmap follows real clinics, not a sales quota. Features ship because a practice needed them.",
+ "Trust is inspectable. The code is public. You can see exactly what happens to a patient record.",
+ ] },
+ { type: "p", text: "OpenVPM is our attempt to prove this can exist and be good β not a stripped-down toy, but a modern PIMS with a real API that a clinic could actually run. It's MIT licensed and it always will be." },
+ { type: "p", text: "We don't think we have all the answers. We think the answers come faster in the open. If you run a clinic, build in this space, or just have opinions about how it should work, we want them β the harder the better." },
+ ],
+ },
+ {
+ slug: "own-your-data-a-second-pims-you-control",
+ title: "Own your data: a second PIMS you control",
+ date: "June 3, 2026",
+ author: "Evan Gauer",
+ excerpt:
+ "You don't have to rip out the system you run today to start owning your data. Connect a second PIMS β one you control β alongside it.",
+ readingMinutes: 5,
+ content: [
+ { type: "p", text: "The most common reaction we hear from practices is some version of: \"I love the idea, but changing my PIMS is a nightmare I'm not signing up for.\" That's not resistance β it's wisdom. A PIMS migration is one of the riskiest things a clinic can do. So we stopped asking for one." },
+ { type: "h2", text: "The model: connect, don't switch" },
+ { type: "p", text: "Instead of rip-and-replace, picture a second PIMS that runs alongside the one you already use β and that you fully own. You connect it with an API key, your data flows in, and now you have a live, exportable copy of your practice's records in a system you control. No migration weekend. No retraining the front desk. Your incumbent keeps doing its job while you quietly gain leverage over your own data." },
+ { type: "ul", items: [
+ "Attach your existing PIMS by API key and mirror your records into a system you own.",
+ "Build on the open API β reminders, analytics, AI agents β without asking a vendor for permission.",
+ "Export everything, anytime. The whole point is that leaving is always easy.",
+ "When you're ready, run it as your primary. Or never. The choice stays yours.",
+ ] },
+ { type: "h2", text: "Where this goes" },
+ { type: "p", text: "The near-term is self-hostable and open: clone it, run it, connect it. The next step is making it effortless β a hosted option where a clinic logs in, attaches their current system, and watches their owned copy populate, no DevOps required. Same open core underneath; we just run the boring parts for you." },
+ { type: "quote", text: "Owning your data shouldn't require a migration. It should require an API key." },
+ { type: "p", text: "This is the part we're actively building, and it's where outside input matters most. If your PIMS has an API we should mirror, tell us. If it doesn't, tell us that too β that's a story worth telling." },
+ ],
+ },
+ {
+ slug: "agents-belong-in-the-back-office",
+ title: "Agents belong in the back office, not just the chat box",
+ date: "June 3, 2026",
+ author: "Evan Gauer",
+ excerpt:
+ "The exciting thing about AI in veterinary medicine isn't a chatbot on the website. It's an agent that can actually do the busywork β if the PIMS lets it.",
+ readingMinutes: 4,
+ content: [
+ { type: "p", text: "Most \"AI for vets\" right now is a chat box bolted onto a website. It can answer questions. What it can't do is the thing that would actually help a short-staffed clinic: the work. Surface the patients overdue for vaccines. Draft the recall list. Look up a weight-based dose. Find the open slot and book the visit. That work lives inside the PIMS β and an agent can only do it if the PIMS has a real, write-capable API." },
+ { type: "h2", text: "Why the closed PIMS blocks this" },
+ { type: "p", text: "An agent is only as useful as the tools it can call. If the system of record won't let software write back β create the appointment, record the note, update the record β then the agent is stuck reading. That's the wall most veterinary AI hits today. It's not a model problem. It's an access problem." },
+ { type: "h2", text: "What we're building" },
+ { type: "p", text: "OpenVPM ships with an agent that operates on the practice's own data through the same open API any developer can use. It works through typed tools β find a client, pull a clinical summary, calculate a dose, find an open slot, book it β and every write is gated for a human to confirm. It's scoped to a single practice and fully inspectable, because it's open source." },
+ { type: "ul", items: [
+ "Tools, not guesses β the agent acts on real records or it doesn't act.",
+ "Human-in-the-loop on every write. The clinic stays in control.",
+ "Bring your own model key. Nothing is hidden; the whole thing is auditable.",
+ ] },
+ { type: "p", text: "We think the clinics that win the next decade won't be the ones with the fanciest chatbot. They'll be the ones whose software lets them put the boring, repetitive work on autopilot β safely. That requires an open foundation. So we're building one." },
+ ],
+ },
+];
+
+export function getPost(slug: string): Post | undefined {
+ return posts.find((p) => p.slug === slug);
+}
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 906b7ea..512011f 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -61,6 +61,18 @@ importers:
'@tanstack/react-query':
specifier: ^5.60.0
version: 5.90.21(react@18.3.1)
+ '@tiptap/extension-highlight':
+ specifier: ^2.1.0
+ version: 2.27.2(@tiptap/core@2.27.2(@tiptap/pm@2.27.2))
+ '@tiptap/extension-underline':
+ specifier: ^2.1.0
+ version: 2.27.2(@tiptap/core@2.27.2(@tiptap/pm@2.27.2))
+ '@tiptap/react':
+ specifier: ^2.1.0
+ version: 2.27.2(@tiptap/core@2.27.2(@tiptap/pm@2.27.2))(@tiptap/pm@2.27.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
+ '@tiptap/starter-kit':
+ specifier: ^2.1.0
+ version: 2.27.2
'@trpc/client':
specifier: ^11.0.0
version: 11.13.4(@trpc/server@11.13.4(typescript@5.9.3))(typescript@5.9.3)
@@ -1196,6 +1208,9 @@ packages:
engines: {node: '>=18'}
hasBin: true
+ '@popperjs/core@2.11.8':
+ resolution: {integrity: sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==}
+
'@radix-ui/primitive@1.1.3':
resolution: {integrity: sha512-JTF99U/6XIjCBo0wqkU5sK10glYe27MRRsfwoiq5zzOEZLHU3A3KCMa5X/azekYRCJ0HlwI0crAXS/5dEHTzDg==}
@@ -1718,6 +1733,9 @@ packages:
peerDependencies:
react: ^18.0 || ^19.0 || ^19.0.0-rc
+ '@remirror/core-constants@3.0.0':
+ resolution: {integrity: sha512-42aWfPrimMfDKDi4YegyS7x+/0tlzaqwPQCULLanv3DMIlu96KTJR0fM5isWX2UViOqlGnX6YFgqWepcX+XMNg==}
+
'@rollup/rollup-android-arm-eabi@4.61.0':
resolution: {integrity: sha512-dnxczajOqt0gesZlN5pGQ1s1imQVrsmCw5G2Ci4oM+0WvNz3pyRnlWrT7McoZIb8VlFwCawdmbWRmxRn7HI+VQ==}
cpu: [arm]
@@ -2079,6 +2097,147 @@ packages:
peerDependencies:
react: ^18 || ^19
+ '@tiptap/core@2.27.2':
+ resolution: {integrity: sha512-ABL1N6eoxzDzC1bYvkMbvyexHacszsKdVPYqhl5GwHLOvpZcv9VE9QaKwDILTyz5voCA0lGcAAXZp+qnXOk5lQ==}
+ peerDependencies:
+ '@tiptap/pm': ^2.7.0
+
+ '@tiptap/extension-blockquote@2.27.2':
+ resolution: {integrity: sha512-oIGZgiAeA4tG3YxbTDfrmENL4/CIwGuP3THtHsNhwRqwsl9SfMk58Ucopi2GXTQSdYXpRJ0ahE6nPqB5D6j/Zw==}
+ peerDependencies:
+ '@tiptap/core': ^2.7.0
+
+ '@tiptap/extension-bold@2.27.2':
+ resolution: {integrity: sha512-bR7J5IwjCGQ0s3CIxyMvOCnMFMzIvsc5OVZKscTN5UkXzFsaY6muUAIqtKxayBUucjtUskm5qZowJITCeCb1/A==}
+ peerDependencies:
+ '@tiptap/core': ^2.7.0
+
+ '@tiptap/extension-bubble-menu@2.27.2':
+ resolution: {integrity: sha512-VkwlCOcr0abTBGzjPXklJ92FCowG7InU8+Od9FyApdLNmn0utRYGRhw0Zno6VgE9EYr1JY4BRnuSa5f9wlR72w==}
+ peerDependencies:
+ '@tiptap/core': ^2.7.0
+ '@tiptap/pm': ^2.7.0
+
+ '@tiptap/extension-bullet-list@2.27.2':
+ resolution: {integrity: sha512-gmFuKi97u5f8uFc/GQs+zmezjiulZmFiDYTh3trVoLRoc2SAHOjGEB7qxdx7dsqmMN7gwiAWAEVurLKIi1lnnw==}
+ peerDependencies:
+ '@tiptap/core': ^2.7.0
+
+ '@tiptap/extension-code-block@2.27.2':
+ resolution: {integrity: sha512-KgvdQHS4jXr79aU3wZOGBIZYYl9vCB7uDEuRFV4so2rYrfmiYMw3T8bTnlNEEGe4RUeAms1i4fdwwvQp9nR1Dw==}
+ peerDependencies:
+ '@tiptap/core': ^2.7.0
+ '@tiptap/pm': ^2.7.0
+
+ '@tiptap/extension-code@2.27.2':
+ resolution: {integrity: sha512-7X9AgwqiIGXoZX7uvdHQsGsjILnN/JaEVtqfXZnPECzKGaWHeK/Ao4sYvIIIffsyZJA8k5DC7ny2/0sAgr2TuA==}
+ peerDependencies:
+ '@tiptap/core': ^2.7.0
+
+ '@tiptap/extension-document@2.27.2':
+ resolution: {integrity: sha512-CFhAYsPnyYnosDC4639sCJnBUnYH4Cat9qH5NZWHVvdgtDwu8GZgZn2eSzaKSYXWH1vJ9DSlCK+7UyC3SNXIBA==}
+ peerDependencies:
+ '@tiptap/core': ^2.7.0
+
+ '@tiptap/extension-dropcursor@2.27.2':
+ resolution: {integrity: sha512-oEu/OrktNoQXq1x29NnH/GOIzQZm8ieTQl3FK27nxfBPA89cNoH4mFEUmBL5/OFIENIjiYG3qWpg6voIqzswNw==}
+ peerDependencies:
+ '@tiptap/core': ^2.7.0
+ '@tiptap/pm': ^2.7.0
+
+ '@tiptap/extension-floating-menu@2.27.2':
+ resolution: {integrity: sha512-GUN6gPIGXS7ngRJOwdSmtBRBDt9Kt9CM/9pSwKebhLJ+honFoNA+Y6IpVyDvvDMdVNgBchiJLs6qA5H97gAePQ==}
+ peerDependencies:
+ '@tiptap/core': ^2.7.0
+ '@tiptap/pm': ^2.7.0
+
+ '@tiptap/extension-gapcursor@2.27.2':
+ resolution: {integrity: sha512-/c9VF1HBxj+AP54XGVgCmD9bEGYc5w5OofYCFQgM7l7PB1J00A4vOke0oPkHJnqnOOyPlFaxO/7N6l3XwFcnKA==}
+ peerDependencies:
+ '@tiptap/core': ^2.7.0
+ '@tiptap/pm': ^2.7.0
+
+ '@tiptap/extension-hard-break@2.27.2':
+ resolution: {integrity: sha512-kSRVGKlCYK6AGR0h8xRkk0WOFGXHIIndod3GKgWU49APuIGDiXd8sziXsSlniUsWmqgDmDXcNnSzPcV7AQ8YNg==}
+ peerDependencies:
+ '@tiptap/core': ^2.7.0
+
+ '@tiptap/extension-heading@2.27.2':
+ resolution: {integrity: sha512-iM3yeRWuuQR/IRQ1djwNooJGfn9Jts9zF43qZIUf+U2NY8IlvdNsk2wTOdBgh6E0CamrStPxYGuln3ZS4fuglw==}
+ peerDependencies:
+ '@tiptap/core': ^2.7.0
+
+ '@tiptap/extension-highlight@2.27.2':
+ resolution: {integrity: sha512-ZjlktDdMjruMJFAVz0TbQf0v92Jqkc7Ri1iZJqBXuLid+r+GxUzl2CVAV7qq5yagkGQgvAG+WGsMk880HgR3MA==}
+ peerDependencies:
+ '@tiptap/core': ^2.7.0
+
+ '@tiptap/extension-history@2.27.2':
+ resolution: {integrity: sha512-+hSyqERoFNTWPiZx4/FCyZ/0eFqB9fuMdTB4AC/q9iwu3RNWAQtlsJg5230bf/qmyO6bZxRUc0k8p4hrV6ybAw==}
+ peerDependencies:
+ '@tiptap/core': ^2.7.0
+ '@tiptap/pm': ^2.7.0
+
+ '@tiptap/extension-horizontal-rule@2.27.2':
+ resolution: {integrity: sha512-WGWUSgX+jCsbtf9Y9OCUUgRZYuwjVoieW5n6mAUohJ9/6gc6sGIOrUpBShf+HHo6WD+gtQjRd+PssmX3NPWMpg==}
+ peerDependencies:
+ '@tiptap/core': ^2.7.0
+ '@tiptap/pm': ^2.7.0
+
+ '@tiptap/extension-italic@2.27.2':
+ resolution: {integrity: sha512-1OFsw2SZqfaqx5Fa5v90iNlPRcqyt+lVSjBwTDzuPxTPFY4Q0mL89mKgkq2gVHYNCiaRkXvFLDxaSvBWbmthgg==}
+ peerDependencies:
+ '@tiptap/core': ^2.7.0
+
+ '@tiptap/extension-list-item@2.27.2':
+ resolution: {integrity: sha512-eJNee7IEGXMnmygM5SdMGDC8m/lMWmwNGf9fPCK6xk0NxuQRgmZHL6uApKcdH6gyNcRPHCqvTTkhEP7pbny/fg==}
+ peerDependencies:
+ '@tiptap/core': ^2.7.0
+
+ '@tiptap/extension-ordered-list@2.27.2':
+ resolution: {integrity: sha512-M7A4tLGJcLPYdLC4CI2Gwl8LOrENQW59u3cMVa+KkwG1hzSJyPsbDpa1DI6oXPC2WtYiTf22zrbq3gVvH+KA2w==}
+ peerDependencies:
+ '@tiptap/core': ^2.7.0
+
+ '@tiptap/extension-paragraph@2.27.2':
+ resolution: {integrity: sha512-elYVn2wHJJ+zB9LESENWOAfI4TNT0jqEN34sMA/hCtA4im1ZG2DdLHwkHIshj/c4H0dzQhmsS/YmNC5Vbqab/A==}
+ peerDependencies:
+ '@tiptap/core': ^2.7.0
+
+ '@tiptap/extension-strike@2.27.2':
+ resolution: {integrity: sha512-HHIjhafLhS2lHgfAsCwC1okqMsQzR4/mkGDm4M583Yftyjri1TNA7lzhzXWRFWiiMfJxKtdjHjUAQaHuteRTZw==}
+ peerDependencies:
+ '@tiptap/core': ^2.7.0
+
+ '@tiptap/extension-text-style@2.27.2':
+ resolution: {integrity: sha512-Omk+uxjJLyEY69KStpCw5fA9asvV+MGcAX2HOxyISDFoLaL49TMrNjhGAuz09P1L1b0KGXo4ml7Q3v/Lfy4WPA==}
+ peerDependencies:
+ '@tiptap/core': ^2.7.0
+
+ '@tiptap/extension-text@2.27.2':
+ resolution: {integrity: sha512-Xk7nYcigljAY0GO9hAQpZ65ZCxqOqaAlTPDFcKerXmlkQZP/8ndx95OgUb1Xf63kmPOh3xypurGS2is3v0MXSA==}
+ peerDependencies:
+ '@tiptap/core': ^2.7.0
+
+ '@tiptap/extension-underline@2.27.2':
+ resolution: {integrity: sha512-gPOsbAcw1S07ezpAISwoO8f0RxpjcSH7VsHEFDVuXm4ODE32nhvSinvHQjv2icRLOXev+bnA7oIBu7Oy859gWQ==}
+ peerDependencies:
+ '@tiptap/core': ^2.7.0
+
+ '@tiptap/pm@2.27.2':
+ resolution: {integrity: sha512-kaEg7BfiJPDQMKbjVIzEPO3wlcA+pZb2tlcK9gPrdDnEFaec2QTF1sXz2ak2IIb2curvnIrQ4yrfHgLlVA72wA==}
+
+ '@tiptap/react@2.27.2':
+ resolution: {integrity: sha512-0EAs8Cpkfbvben1PZ34JN2Nd79Dhioynm2jML27DBbf1VWPk+FFWFGTMLUT0bu+Np5iVxio8fqV9t0mc4D6thA==}
+ peerDependencies:
+ '@tiptap/core': ^2.7.0
+ '@tiptap/pm': ^2.7.0
+ react: ^17.0.0 || ^18.0.0 || ^19.0.0
+ react-dom: ^17.0.0 || ^18.0.0 || ^19.0.0
+
+ '@tiptap/starter-kit@2.27.2':
+ resolution: {integrity: sha512-bb0gJvPoDuyRUQ/iuN52j1//EtWWttw+RXAv1uJxfR0uKf8X7uAqzaOOgwjknoCIDC97+1YHwpGdnRjpDkOBxw==}
+
'@trpc/client@11.13.4':
resolution: {integrity: sha512-AOM7u2blAjjpAzEyDXm4bk8f1HML0sFLuSXPsqZHQX3XCIVo7+mlArEAGMbwEtTwW8hUocI0i3/9tVYUF4Nu0g==}
peerDependencies:
@@ -2149,6 +2308,15 @@ packages:
'@types/estree@1.0.9':
resolution: {integrity: sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==}
+ '@types/linkify-it@5.0.0':
+ resolution: {integrity: sha512-sVDA58zAw4eWAffKOaQH5/5j3XeayukzDk+ewSsnv3p4yJEZHCCzMDiZM8e0OUrRvmpGZ85jf4yDHkHsgBNr9Q==}
+
+ '@types/markdown-it@14.1.2':
+ resolution: {integrity: sha512-promo4eFwuiW+TfGxhi+0x3czqTYJkG8qB17ZUJiVF10Xm7NLVRSLUsfRTU/6h1e24VvRnXCx+hG7li58lkzog==}
+
+ '@types/mdurl@2.0.0':
+ resolution: {integrity: sha512-RGdgjQUZba5p6QEFAVx2OGb8rQDL/cPRG7GiedRzMcJ1tYnUANBncjbSB1NRGwbvjcPeikRABz2nshyPk1bhWg==}
+
'@types/node@20.19.37':
resolution: {integrity: sha512-8kzdPJ3FsNsVIurqBs7oodNnCEVbni9yUEkaHbgptDACOPW04jimGagZ51E6+lXUwJjgnBw+hyko/lkFWCldqw==}
@@ -2172,6 +2340,9 @@ packages:
'@types/trusted-types@2.0.7':
resolution: {integrity: sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==}
+ '@types/use-sync-external-store@0.0.6':
+ resolution: {integrity: sha512-zFDAD+tlpf2r4asuHEj0XH6pY6i0g5NeAHPn+15wk3BV6JA69eERFXC1gyGThDkVa1zCyKr5jox1+2LbV/AMLg==}
+
'@vercel/analytics@2.0.1':
resolution: {integrity: sha512-MTQG6V9qQrt1tsDeF+2Uoo5aPjqbVPys1xvnIftXSJYG2SrwXRHnqEvVoYID7BTruDz4lCd2Z7rM1BdkUehk2g==}
peerDependencies:
@@ -2264,6 +2435,9 @@ packages:
arg@5.0.2:
resolution: {integrity: sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==}
+ argparse@2.0.1:
+ resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==}
+
aria-hidden@1.2.6:
resolution: {integrity: sha512-ik3ZgC9dY/lYVVM++OISsaYDeg1tb0VtP5uL3ouh1koGOaUMDPpbFIei4JkFimWUFPn90sbMNMXQAIVOlnYKJA==}
engines: {node: '>=10'}
@@ -2413,6 +2587,9 @@ packages:
core-js@3.49.0:
resolution: {integrity: sha512-es1U2+YTtzpwkxVLwAFdSpaIMyQaq0PBgm3YD1W3Qpsn1NAmO3KSgZfu+oGSWVu6NvLHoHCV/aYcsE5wiB7ALg==}
+ crelt@1.0.6:
+ resolution: {integrity: sha512-VQ2MBenTq1fWZUH9DJNGti7kKv6EeAuYr3cLwxUWhIu1baTaXh4Ib5W2CqHVqib4/MqbYGJqiL3Zb8GJZr3l4g==}
+
cross-spawn@7.0.6:
resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==}
engines: {node: '>= 8'}
@@ -2698,6 +2875,10 @@ packages:
resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==}
engines: {node: '>=6'}
+ escape-string-regexp@4.0.0:
+ resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==}
+ engines: {node: '>=10'}
+
estree-walker@3.0.3:
resolution: {integrity: sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==}
@@ -2711,6 +2892,9 @@ packages:
fast-deep-equal@2.0.1:
resolution: {integrity: sha512-bCK/2Z4zLidyB4ReuIsvALH6w31YfAQDmXMqMx6FyfHqvBxtjC0eRumeSu4Bs3XtXwpyIywtSTrVT99BxY1f9w==}
+ fast-deep-equal@3.1.3:
+ resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==}
+
fast-equals@5.4.0:
resolution: {integrity: sha512-jt2DW/aNFNwke7AUd+Z+e6pz39KO5rzdbbFCg2sGafS4mk13MI7Z8O5z9cADNn5lhGODIgLwug6TZO2ctf7kcw==}
engines: {node: '>=6.0.0'}
@@ -2939,6 +3123,9 @@ packages:
lines-and-columns@1.2.4:
resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==}
+ linkify-it@5.0.1:
+ resolution: {integrity: sha512-wVoTjP4Q6R0NW5hiZkVJaFZPWgtXfoGF+6LucL3/FtiNjmcHhYjEr5f1Kqjirc1nBW07J/ZuRFumqr2oqccEWg==}
+
lodash.includes@4.3.0:
resolution: {integrity: sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==}
@@ -2985,6 +3172,10 @@ packages:
magic-string@0.30.21:
resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==}
+ markdown-it@14.2.0:
+ resolution: {integrity: sha512-1TGiQiJVRQ3NPmZH6sx5Cfnmg6GQm9jvC1ch4TK511NjSJvjzKLzn5pPfZRNZkRPZP0HqCioSndqH8v2nRaWVQ==}
+ hasBin: true
+
marked@7.0.4:
resolution: {integrity: sha512-t8eP0dXRJMtMvBojtkcsA7n48BkauktUKzfkPSCq85ZMTJ0v76Rke4DYz01omYpPTUh4p/f7HePgRo3ebG8+QQ==}
engines: {node: '>= 16'}
@@ -2999,6 +3190,9 @@ packages:
peerDependencies:
react: 18.x
+ mdurl@2.0.0:
+ resolution: {integrity: sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w==}
+
merge2@1.4.1:
resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==}
engines: {node: '>= 8'}
@@ -3110,6 +3304,9 @@ packages:
openid-client@5.7.1:
resolution: {integrity: sha512-jDBPgSVfTnkIh71Hg9pRvtJc6wTwqjRkN88+gCFtYWrlP4Yx2Dsrow8uPi3qLr/aeymPF3o2+dS+wOpglK04ew==}
+ orderedmap@2.1.1:
+ resolution: {integrity: sha512-TvAWxi0nDe1j/rtMcWcIj94+Ffe6n7zhow33h40SKxmsmozs6dz/e+EajymfoFcHd7sxNn8yHM8839uixMOV6g==}
+
package-json-from-dist@1.0.1:
resolution: {integrity: sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==}
@@ -3252,12 +3449,74 @@ packages:
prop-types@15.8.1:
resolution: {integrity: sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==}
+ prosemirror-changeset@2.4.1:
+ resolution: {integrity: sha512-96WBLhOaYhJ+kPhLg3uW359Tz6I/MfcrQfL4EGv4SrcqKEMC1gmoGrXHecPE8eOwTVCJ4IwgfzM8fFad25wNfw==}
+
+ prosemirror-collab@1.3.1:
+ resolution: {integrity: sha512-4SnynYR9TTYaQVXd/ieUvsVV4PDMBzrq2xPUWutHivDuOshZXqQ5rGbZM84HEaXKbLdItse7weMGOUdDVcLKEQ==}
+
+ prosemirror-commands@1.7.1:
+ resolution: {integrity: sha512-rT7qZnQtx5c0/y/KlYaGvtG411S97UaL6gdp6RIZ23DLHanMYLyfGBV5DtSnZdthQql7W+lEVbpSfwtO8T+L2w==}
+
+ prosemirror-dropcursor@1.8.2:
+ resolution: {integrity: sha512-CCk6Gyx9+Tt2sbYk5NK0nB1ukHi2ryaRgadV/LvyNuO3ena1payM2z6Cg0vO1ebK8cxbzo41ku2DE5Axj1Zuiw==}
+
+ prosemirror-gapcursor@1.4.1:
+ resolution: {integrity: sha512-pMdYaEnjNMSwl11yjEGtgTmLkR08m/Vl+Jj443167p9eB3HVQKhYCc4gmHVDsLPODfZfjr/MmirsdyZziXbQKw==}
+
+ prosemirror-history@1.5.0:
+ resolution: {integrity: sha512-zlzTiH01eKA55UAf1MEjtssJeHnGxO0j4K4Dpx+gnmX9n+SHNlDqI2oO1Kv1iPN5B1dm5fsljCfqKF9nFL6HRg==}
+
+ prosemirror-inputrules@1.5.1:
+ resolution: {integrity: sha512-7wj4uMjKaXWAQ1CDgxNzNtR9AlsuwzHfdFH1ygEHA2KHF2DOEaXl1CJfNPAKCg9qNEh4rum975QLaCiQPyY6Fw==}
+
+ prosemirror-keymap@1.2.3:
+ resolution: {integrity: sha512-4HucRlpiLd1IPQQXNqeo81BGtkY8Ai5smHhKW9jjPKRc2wQIxksg7Hl1tTI2IfT2B/LgX6bfYvXxEpJl7aKYKw==}
+
+ prosemirror-markdown@1.13.4:
+ resolution: {integrity: sha512-D98dm4cQ3Hs6EmjK500TdAOew4Z03EV71ajEFiWra3Upr7diytJsjF4mPV2dW+eK5uNectiRj0xFxYI9NLXDbw==}
+
+ prosemirror-menu@1.3.2:
+ resolution: {integrity: sha512-6VgUJTYod0nMBlCaYJGhXGLu7Gt4AvcwcOq0YfJCY/6Uh+3S7UsWhpy6rJFCBFOmonq1hD8KyWOtZhkppd4YPg==}
+
+ prosemirror-model@1.25.7:
+ resolution: {integrity: sha512-A79aN8QEFUwI6cax8Yq4Rpcx1TJZ3Kagn+ii7qLo4/V8H3mMiHrhFyhTyHHvpSnOgMPpWiDGSwM3etwrxE50ug==}
+
+ prosemirror-schema-basic@1.2.4:
+ resolution: {integrity: sha512-ELxP4TlX3yr2v5rM7Sb70SqStq5NvI15c0j9j/gjsrO5vaw+fnnpovCLEGIcpeGfifkuqJwl4fon6b+KdrODYQ==}
+
+ prosemirror-schema-list@1.5.1:
+ resolution: {integrity: sha512-927lFx/uwyQaGwJxLWCZRkjXG0p48KpMj6ueoYiu4JX05GGuGcgzAy62dfiV8eFZftgyBUvLx76RsMe20fJl+Q==}
+
+ prosemirror-state@1.4.4:
+ resolution: {integrity: sha512-6jiYHH2CIGbCfnxdHbXZ12gySFY/fz/ulZE333G6bPqIZ4F+TXo9ifiR86nAHpWnfoNjOb3o5ESi7J8Uz1jXHw==}
+
+ prosemirror-tables@1.8.5:
+ resolution: {integrity: sha512-V/0cDCsHKHe/tfWkeCmthNUcEp1IVO3p6vwN8XtwE9PZQLAZJigbw3QoraAdfJPir4NKJtNvOB8oYGKRl+t0Dw==}
+
+ prosemirror-trailing-node@3.0.0:
+ resolution: {integrity: sha512-xiun5/3q0w5eRnGYfNlW1uU9W6x5MoFKWwq/0TIRgt09lv7Hcser2QYV8t4muXbEr+Fwo0geYn79Xs4GKywrRQ==}
+ peerDependencies:
+ prosemirror-model: ^1.22.1
+ prosemirror-state: ^1.4.2
+ prosemirror-view: ^1.33.8
+
+ prosemirror-transform@1.12.0:
+ resolution: {integrity: sha512-GxboyN4AMIsoHNtz5uf2r2Ru551i5hWeCMD6E2Ib4Eogqoub0NflniaBPVQ4MrGE5yZ8JV9tUHg9qcZTTrcN4w==}
+
+ prosemirror-view@1.41.8:
+ resolution: {integrity: sha512-TnKDdohEatgyZNGCDWIdccOHXhYloJwbwU+phw/a23KBvJIR9lWQWW7WHHK3vBdOLDNuF7TaX98GObUZOWkOnA==}
+
proto-list@1.2.4:
resolution: {integrity: sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA==}
proxy-from-env@1.1.0:
resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==}
+ punycode.js@2.3.1:
+ resolution: {integrity: sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==}
+ engines: {node: '>=6'}
+
qs@6.15.0:
resolution: {integrity: sha512-mAZTtNCeetKMH+pSjrb76NAM8V9a05I9aBZOHztWy/UqcJdQYNsf59vrRKWnojAT9Y+GbIvoTBC++CPHqpDBhQ==}
engines: {node: '>=0.6'}
@@ -3378,6 +3637,9 @@ packages:
engines: {node: '>=18.0.0', npm: '>=8.0.0'}
hasBin: true
+ rope-sequence@1.3.4:
+ resolution: {integrity: sha512-UT5EDe2cu2E/6O4igUr5PSFs23nvvukicWHx6GnOPlHAiiYbzNuCRQCuiUdHJQcqKalLKlrYJnjY0ySGsXNQXQ==}
+
run-parallel@1.2.0:
resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==}
@@ -3576,6 +3838,9 @@ packages:
resolution: {integrity: sha512-n1cw8k1k0x4pgA2+9XrOkFydTerNcJ1zWCO5Nn9scWHTD+5tp8dghT2x1uduQePZTZgd3Tupf+x9BxJjeJi77Q==}
engines: {node: '>=14.0.0'}
+ tippy.js@6.3.7:
+ resolution: {integrity: sha512-E1d3oP2emgJ9dRQZdf3Kkn0qJgI6ZLpyS5z6ZkY1DF3kaQaBsGZsndEpHwx+eC+tYM41HaSNvNtLx8tU57FzTQ==}
+
to-regex-range@5.0.1:
resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==}
engines: {node: '>=8.0'}
@@ -3637,6 +3902,9 @@ packages:
engines: {node: '>=14.17'}
hasBin: true
+ uc.micro@2.1.0:
+ resolution: {integrity: sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==}
+
undici-types@6.21.0:
resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==}
@@ -3749,6 +4017,9 @@ packages:
jsdom:
optional: true
+ w3c-keyname@2.2.8:
+ resolution: {integrity: sha512-dpojBhNsCNN7T82Tm7k26A6G9ML3NkhDsnw9n/eoxSRlVBB4CEtIQ/KTCLI2Fwf3ataSXRhYFkQi3SlnFwPvPQ==}
+
which@2.0.2:
resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==}
engines: {node: '>= 8'}
@@ -4665,6 +4936,8 @@ snapshots:
dependencies:
playwright: 1.58.2
+ '@popperjs/core@2.11.8': {}
+
'@radix-ui/primitive@1.1.3': {}
'@radix-ui/react-arrow@1.1.7(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
@@ -5158,6 +5431,8 @@ snapshots:
dependencies:
react: 18.3.1
+ '@remirror/core-constants@3.0.0': {}
+
'@rollup/rollup-android-arm-eabi@4.61.0':
optional: true
@@ -5593,6 +5868,168 @@ snapshots:
'@tanstack/query-core': 5.90.20
react: 18.3.1
+ '@tiptap/core@2.27.2(@tiptap/pm@2.27.2)':
+ dependencies:
+ '@tiptap/pm': 2.27.2
+
+ '@tiptap/extension-blockquote@2.27.2(@tiptap/core@2.27.2(@tiptap/pm@2.27.2))':
+ dependencies:
+ '@tiptap/core': 2.27.2(@tiptap/pm@2.27.2)
+
+ '@tiptap/extension-bold@2.27.2(@tiptap/core@2.27.2(@tiptap/pm@2.27.2))':
+ dependencies:
+ '@tiptap/core': 2.27.2(@tiptap/pm@2.27.2)
+
+ '@tiptap/extension-bubble-menu@2.27.2(@tiptap/core@2.27.2(@tiptap/pm@2.27.2))(@tiptap/pm@2.27.2)':
+ dependencies:
+ '@tiptap/core': 2.27.2(@tiptap/pm@2.27.2)
+ '@tiptap/pm': 2.27.2
+ tippy.js: 6.3.7
+
+ '@tiptap/extension-bullet-list@2.27.2(@tiptap/core@2.27.2(@tiptap/pm@2.27.2))':
+ dependencies:
+ '@tiptap/core': 2.27.2(@tiptap/pm@2.27.2)
+
+ '@tiptap/extension-code-block@2.27.2(@tiptap/core@2.27.2(@tiptap/pm@2.27.2))(@tiptap/pm@2.27.2)':
+ dependencies:
+ '@tiptap/core': 2.27.2(@tiptap/pm@2.27.2)
+ '@tiptap/pm': 2.27.2
+
+ '@tiptap/extension-code@2.27.2(@tiptap/core@2.27.2(@tiptap/pm@2.27.2))':
+ dependencies:
+ '@tiptap/core': 2.27.2(@tiptap/pm@2.27.2)
+
+ '@tiptap/extension-document@2.27.2(@tiptap/core@2.27.2(@tiptap/pm@2.27.2))':
+ dependencies:
+ '@tiptap/core': 2.27.2(@tiptap/pm@2.27.2)
+
+ '@tiptap/extension-dropcursor@2.27.2(@tiptap/core@2.27.2(@tiptap/pm@2.27.2))(@tiptap/pm@2.27.2)':
+ dependencies:
+ '@tiptap/core': 2.27.2(@tiptap/pm@2.27.2)
+ '@tiptap/pm': 2.27.2
+
+ '@tiptap/extension-floating-menu@2.27.2(@tiptap/core@2.27.2(@tiptap/pm@2.27.2))(@tiptap/pm@2.27.2)':
+ dependencies:
+ '@tiptap/core': 2.27.2(@tiptap/pm@2.27.2)
+ '@tiptap/pm': 2.27.2
+ tippy.js: 6.3.7
+
+ '@tiptap/extension-gapcursor@2.27.2(@tiptap/core@2.27.2(@tiptap/pm@2.27.2))(@tiptap/pm@2.27.2)':
+ dependencies:
+ '@tiptap/core': 2.27.2(@tiptap/pm@2.27.2)
+ '@tiptap/pm': 2.27.2
+
+ '@tiptap/extension-hard-break@2.27.2(@tiptap/core@2.27.2(@tiptap/pm@2.27.2))':
+ dependencies:
+ '@tiptap/core': 2.27.2(@tiptap/pm@2.27.2)
+
+ '@tiptap/extension-heading@2.27.2(@tiptap/core@2.27.2(@tiptap/pm@2.27.2))':
+ dependencies:
+ '@tiptap/core': 2.27.2(@tiptap/pm@2.27.2)
+
+ '@tiptap/extension-highlight@2.27.2(@tiptap/core@2.27.2(@tiptap/pm@2.27.2))':
+ dependencies:
+ '@tiptap/core': 2.27.2(@tiptap/pm@2.27.2)
+
+ '@tiptap/extension-history@2.27.2(@tiptap/core@2.27.2(@tiptap/pm@2.27.2))(@tiptap/pm@2.27.2)':
+ dependencies:
+ '@tiptap/core': 2.27.2(@tiptap/pm@2.27.2)
+ '@tiptap/pm': 2.27.2
+
+ '@tiptap/extension-horizontal-rule@2.27.2(@tiptap/core@2.27.2(@tiptap/pm@2.27.2))(@tiptap/pm@2.27.2)':
+ dependencies:
+ '@tiptap/core': 2.27.2(@tiptap/pm@2.27.2)
+ '@tiptap/pm': 2.27.2
+
+ '@tiptap/extension-italic@2.27.2(@tiptap/core@2.27.2(@tiptap/pm@2.27.2))':
+ dependencies:
+ '@tiptap/core': 2.27.2(@tiptap/pm@2.27.2)
+
+ '@tiptap/extension-list-item@2.27.2(@tiptap/core@2.27.2(@tiptap/pm@2.27.2))':
+ dependencies:
+ '@tiptap/core': 2.27.2(@tiptap/pm@2.27.2)
+
+ '@tiptap/extension-ordered-list@2.27.2(@tiptap/core@2.27.2(@tiptap/pm@2.27.2))':
+ dependencies:
+ '@tiptap/core': 2.27.2(@tiptap/pm@2.27.2)
+
+ '@tiptap/extension-paragraph@2.27.2(@tiptap/core@2.27.2(@tiptap/pm@2.27.2))':
+ dependencies:
+ '@tiptap/core': 2.27.2(@tiptap/pm@2.27.2)
+
+ '@tiptap/extension-strike@2.27.2(@tiptap/core@2.27.2(@tiptap/pm@2.27.2))':
+ dependencies:
+ '@tiptap/core': 2.27.2(@tiptap/pm@2.27.2)
+
+ '@tiptap/extension-text-style@2.27.2(@tiptap/core@2.27.2(@tiptap/pm@2.27.2))':
+ dependencies:
+ '@tiptap/core': 2.27.2(@tiptap/pm@2.27.2)
+
+ '@tiptap/extension-text@2.27.2(@tiptap/core@2.27.2(@tiptap/pm@2.27.2))':
+ dependencies:
+ '@tiptap/core': 2.27.2(@tiptap/pm@2.27.2)
+
+ '@tiptap/extension-underline@2.27.2(@tiptap/core@2.27.2(@tiptap/pm@2.27.2))':
+ dependencies:
+ '@tiptap/core': 2.27.2(@tiptap/pm@2.27.2)
+
+ '@tiptap/pm@2.27.2':
+ dependencies:
+ prosemirror-changeset: 2.4.1
+ prosemirror-collab: 1.3.1
+ prosemirror-commands: 1.7.1
+ prosemirror-dropcursor: 1.8.2
+ prosemirror-gapcursor: 1.4.1
+ prosemirror-history: 1.5.0
+ prosemirror-inputrules: 1.5.1
+ prosemirror-keymap: 1.2.3
+ prosemirror-markdown: 1.13.4
+ prosemirror-menu: 1.3.2
+ prosemirror-model: 1.25.7
+ prosemirror-schema-basic: 1.2.4
+ prosemirror-schema-list: 1.5.1
+ prosemirror-state: 1.4.4
+ prosemirror-tables: 1.8.5
+ prosemirror-trailing-node: 3.0.0(prosemirror-model@1.25.7)(prosemirror-state@1.4.4)(prosemirror-view@1.41.8)
+ prosemirror-transform: 1.12.0
+ prosemirror-view: 1.41.8
+
+ '@tiptap/react@2.27.2(@tiptap/core@2.27.2(@tiptap/pm@2.27.2))(@tiptap/pm@2.27.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
+ dependencies:
+ '@tiptap/core': 2.27.2(@tiptap/pm@2.27.2)
+ '@tiptap/extension-bubble-menu': 2.27.2(@tiptap/core@2.27.2(@tiptap/pm@2.27.2))(@tiptap/pm@2.27.2)
+ '@tiptap/extension-floating-menu': 2.27.2(@tiptap/core@2.27.2(@tiptap/pm@2.27.2))(@tiptap/pm@2.27.2)
+ '@tiptap/pm': 2.27.2
+ '@types/use-sync-external-store': 0.0.6
+ fast-deep-equal: 3.1.3
+ react: 18.3.1
+ react-dom: 18.3.1(react@18.3.1)
+ use-sync-external-store: 1.6.0(react@18.3.1)
+
+ '@tiptap/starter-kit@2.27.2':
+ dependencies:
+ '@tiptap/core': 2.27.2(@tiptap/pm@2.27.2)
+ '@tiptap/extension-blockquote': 2.27.2(@tiptap/core@2.27.2(@tiptap/pm@2.27.2))
+ '@tiptap/extension-bold': 2.27.2(@tiptap/core@2.27.2(@tiptap/pm@2.27.2))
+ '@tiptap/extension-bullet-list': 2.27.2(@tiptap/core@2.27.2(@tiptap/pm@2.27.2))
+ '@tiptap/extension-code': 2.27.2(@tiptap/core@2.27.2(@tiptap/pm@2.27.2))
+ '@tiptap/extension-code-block': 2.27.2(@tiptap/core@2.27.2(@tiptap/pm@2.27.2))(@tiptap/pm@2.27.2)
+ '@tiptap/extension-document': 2.27.2(@tiptap/core@2.27.2(@tiptap/pm@2.27.2))
+ '@tiptap/extension-dropcursor': 2.27.2(@tiptap/core@2.27.2(@tiptap/pm@2.27.2))(@tiptap/pm@2.27.2)
+ '@tiptap/extension-gapcursor': 2.27.2(@tiptap/core@2.27.2(@tiptap/pm@2.27.2))(@tiptap/pm@2.27.2)
+ '@tiptap/extension-hard-break': 2.27.2(@tiptap/core@2.27.2(@tiptap/pm@2.27.2))
+ '@tiptap/extension-heading': 2.27.2(@tiptap/core@2.27.2(@tiptap/pm@2.27.2))
+ '@tiptap/extension-history': 2.27.2(@tiptap/core@2.27.2(@tiptap/pm@2.27.2))(@tiptap/pm@2.27.2)
+ '@tiptap/extension-horizontal-rule': 2.27.2(@tiptap/core@2.27.2(@tiptap/pm@2.27.2))(@tiptap/pm@2.27.2)
+ '@tiptap/extension-italic': 2.27.2(@tiptap/core@2.27.2(@tiptap/pm@2.27.2))
+ '@tiptap/extension-list-item': 2.27.2(@tiptap/core@2.27.2(@tiptap/pm@2.27.2))
+ '@tiptap/extension-ordered-list': 2.27.2(@tiptap/core@2.27.2(@tiptap/pm@2.27.2))
+ '@tiptap/extension-paragraph': 2.27.2(@tiptap/core@2.27.2(@tiptap/pm@2.27.2))
+ '@tiptap/extension-strike': 2.27.2(@tiptap/core@2.27.2(@tiptap/pm@2.27.2))
+ '@tiptap/extension-text': 2.27.2(@tiptap/core@2.27.2(@tiptap/pm@2.27.2))
+ '@tiptap/extension-text-style': 2.27.2(@tiptap/core@2.27.2(@tiptap/pm@2.27.2))
+ '@tiptap/pm': 2.27.2
+
'@trpc/client@11.13.4(@trpc/server@11.13.4(typescript@5.9.3))(typescript@5.9.3)':
dependencies:
'@trpc/server': 11.13.4(typescript@5.9.3)
@@ -5650,6 +6087,15 @@ snapshots:
'@types/estree@1.0.9': {}
+ '@types/linkify-it@5.0.0': {}
+
+ '@types/markdown-it@14.1.2':
+ dependencies:
+ '@types/linkify-it': 5.0.0
+ '@types/mdurl': 2.0.0
+
+ '@types/mdurl@2.0.0': {}
+
'@types/node@20.19.37':
dependencies:
undici-types: 6.21.0
@@ -5673,6 +6119,8 @@ snapshots:
'@types/trusted-types@2.0.7':
optional: true
+ '@types/use-sync-external-store@0.0.6': {}
+
'@vercel/analytics@2.0.1(next@14.2.35(@playwright/test@1.58.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1)':
optionalDependencies:
next: 14.2.35(@playwright/test@1.58.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
@@ -5745,6 +6193,8 @@ snapshots:
arg@5.0.2: {}
+ argparse@2.0.1: {}
+
aria-hidden@1.2.6:
dependencies:
tslib: 2.8.1
@@ -5905,6 +6355,8 @@ snapshots:
core-js@3.49.0:
optional: true
+ crelt@1.0.6: {}
+
cross-spawn@7.0.6:
dependencies:
path-key: 3.1.1
@@ -6175,6 +6627,8 @@ snapshots:
escalade@3.2.0: {}
+ escape-string-regexp@4.0.0: {}
+
estree-walker@3.0.3:
dependencies:
'@types/estree': 1.0.9
@@ -6185,6 +6639,8 @@ snapshots:
fast-deep-equal@2.0.1: {}
+ fast-deep-equal@3.1.3: {}
+
fast-equals@5.4.0: {}
fast-glob@3.3.3:
@@ -6433,6 +6889,10 @@ snapshots:
lines-and-columns@1.2.4: {}
+ linkify-it@5.0.1:
+ dependencies:
+ uc.micro: 2.1.0
+
lodash.includes@4.3.0: {}
lodash.isboolean@3.0.3: {}
@@ -6469,6 +6929,15 @@ snapshots:
dependencies:
'@jridgewell/sourcemap-codec': 1.5.5
+ markdown-it@14.2.0:
+ dependencies:
+ argparse: 2.0.1
+ entities: 4.5.0
+ linkify-it: 5.0.1
+ mdurl: 2.0.0
+ punycode.js: 2.3.1
+ uc.micro: 2.1.0
+
marked@7.0.4: {}
math-intrinsics@1.1.0: {}
@@ -6478,6 +6947,8 @@ snapshots:
marked: 7.0.4
react: 18.3.1
+ mdurl@2.0.0: {}
+
merge2@1.4.1: {}
micromatch@4.0.8:
@@ -6580,6 +7051,8 @@ snapshots:
object-hash: 2.2.0
oidc-token-hash: 5.2.0
+ orderedmap@2.1.1: {}
+
package-json-from-dist@1.0.1: {}
pako@2.1.0: {}
@@ -6692,10 +7165,115 @@ snapshots:
object-assign: 4.1.1
react-is: 16.13.1
+ prosemirror-changeset@2.4.1:
+ dependencies:
+ prosemirror-transform: 1.12.0
+
+ prosemirror-collab@1.3.1:
+ dependencies:
+ prosemirror-state: 1.4.4
+
+ prosemirror-commands@1.7.1:
+ dependencies:
+ prosemirror-model: 1.25.7
+ prosemirror-state: 1.4.4
+ prosemirror-transform: 1.12.0
+
+ prosemirror-dropcursor@1.8.2:
+ dependencies:
+ prosemirror-state: 1.4.4
+ prosemirror-transform: 1.12.0
+ prosemirror-view: 1.41.8
+
+ prosemirror-gapcursor@1.4.1:
+ dependencies:
+ prosemirror-keymap: 1.2.3
+ prosemirror-model: 1.25.7
+ prosemirror-state: 1.4.4
+ prosemirror-view: 1.41.8
+
+ prosemirror-history@1.5.0:
+ dependencies:
+ prosemirror-state: 1.4.4
+ prosemirror-transform: 1.12.0
+ prosemirror-view: 1.41.8
+ rope-sequence: 1.3.4
+
+ prosemirror-inputrules@1.5.1:
+ dependencies:
+ prosemirror-state: 1.4.4
+ prosemirror-transform: 1.12.0
+
+ prosemirror-keymap@1.2.3:
+ dependencies:
+ prosemirror-state: 1.4.4
+ w3c-keyname: 2.2.8
+
+ prosemirror-markdown@1.13.4:
+ dependencies:
+ '@types/markdown-it': 14.1.2
+ markdown-it: 14.2.0
+ prosemirror-model: 1.25.7
+
+ prosemirror-menu@1.3.2:
+ dependencies:
+ crelt: 1.0.6
+ prosemirror-commands: 1.7.1
+ prosemirror-history: 1.5.0
+ prosemirror-state: 1.4.4
+
+ prosemirror-model@1.25.7:
+ dependencies:
+ orderedmap: 2.1.1
+
+ prosemirror-schema-basic@1.2.4:
+ dependencies:
+ prosemirror-model: 1.25.7
+
+ prosemirror-schema-list@1.5.1:
+ dependencies:
+ prosemirror-model: 1.25.7
+ prosemirror-state: 1.4.4
+ prosemirror-transform: 1.12.0
+
+ prosemirror-state@1.4.4:
+ dependencies:
+ prosemirror-model: 1.25.7
+ prosemirror-transform: 1.12.0
+ prosemirror-view: 1.41.8
+
+ prosemirror-tables@1.8.5:
+ dependencies:
+ prosemirror-keymap: 1.2.3
+ prosemirror-model: 1.25.7
+ prosemirror-state: 1.4.4
+ prosemirror-transform: 1.12.0
+ prosemirror-view: 1.41.8
+
+ prosemirror-trailing-node@3.0.0(prosemirror-model@1.25.7)(prosemirror-state@1.4.4)(prosemirror-view@1.41.8):
+ dependencies:
+ '@remirror/core-constants': 3.0.0
+ escape-string-regexp: 4.0.0
+ prosemirror-model: 1.25.7
+ prosemirror-state: 1.4.4
+ prosemirror-view: 1.41.8
+
+ prosemirror-transform@1.12.0:
+ dependencies:
+ prosemirror-model: 1.25.7
+
+ prosemirror-view@1.41.8:
+ dependencies:
+ prosemirror-model: 1.25.7
+ prosemirror-state: 1.4.4
+ prosemirror-transform: 1.12.0
+
proto-list@1.2.4: {}
proxy-from-env@1.1.0: {}
+ punycode.js@2.3.1: {}
+
qs@6.15.0:
dependencies:
side-channel: 1.1.0
@@ -6848,6 +7426,8 @@ snapshots:
'@rollup/rollup-win32-x64-msvc': 4.61.0
fsevents: 2.3.3
+ rope-sequence@1.3.4: {}
+
run-parallel@1.2.0:
dependencies:
queue-microtask: 1.2.3
@@ -7053,6 +7633,10 @@ snapshots:
tinyspy@3.0.2: {}
+ tippy.js@6.3.7:
+ dependencies:
+ '@popperjs/core': 2.11.8
+
to-regex-range@5.0.1:
dependencies:
is-number: 7.0.0
@@ -7112,6 +7696,8 @@ snapshots:
typescript@5.9.3: {}
+ uc.micro@2.1.0: {}
+
undici-types@6.21.0: {}
update-browserslist-db@1.2.3(browserslist@4.28.1):
@@ -7229,6 +7815,8 @@ snapshots:
- supports-color
- terser
+ w3c-keyname@2.2.8: {}
+
which@2.0.2:
dependencies:
isexe: 2.0.0