vertex-notes 0.1.3 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (40) hide show
  1. package/dist/{chunk-4QLCD6TZ.js → chunk-WM6QVD53.js} +371 -43
  2. package/dist/chunk-WM6QVD53.js.map +1 -0
  3. package/dist/{chunk-DDFOKGIX.js → chunk-XGZKUOFI.js} +2 -2
  4. package/dist/commands/capture.js +2 -2
  5. package/dist/commands/daily.js +2 -2
  6. package/dist/commands/delete.js +2 -2
  7. package/dist/commands/edit.js +3 -5
  8. package/dist/commands/edit.js.map +1 -1
  9. package/dist/commands/export.js +2 -2
  10. package/dist/commands/hello.js +1 -1
  11. package/dist/commands/help.js +23 -14
  12. package/dist/commands/help.js.map +1 -1
  13. package/dist/commands/howto.js +373 -0
  14. package/dist/commands/howto.js.map +1 -0
  15. package/dist/commands/import.js +39 -0
  16. package/dist/commands/import.js.map +1 -0
  17. package/dist/commands/interactive.js +187 -74
  18. package/dist/commands/interactive.js.map +1 -1
  19. package/dist/commands/login.js +6 -2
  20. package/dist/commands/login.js.map +1 -1
  21. package/dist/commands/new.js +2 -2
  22. package/dist/commands/notes.js +2 -2
  23. package/dist/commands/restore.js +2 -2
  24. package/dist/commands/search.js +2 -2
  25. package/dist/commands/status.js +2 -2
  26. package/dist/commands/syntax.js +270 -0
  27. package/dist/commands/syntax.js.map +1 -0
  28. package/dist/commands/tags.js +2 -2
  29. package/dist/commands/today.js +2 -2
  30. package/dist/commands/trash/empty.js +2 -2
  31. package/dist/commands/trash/index.js +2 -2
  32. package/dist/commands/view.js +2 -2
  33. package/dist/lib/client.js +2 -2
  34. package/dist/lib/md-to-tiptap.js +243 -3
  35. package/dist/lib/md-to-tiptap.js.map +1 -1
  36. package/package.json +2 -1
  37. package/dist/chunk-4QLCD6TZ.js.map +0 -1
  38. package/dist/chunk-FWK2J3FR.js +0 -163
  39. package/dist/chunk-FWK2J3FR.js.map +0 -1
  40. /package/dist/{chunk-DDFOKGIX.js.map → chunk-XGZKUOFI.js.map} +0 -0
@@ -253,7 +253,8 @@ function mapTiptapTypeToBlockType(tiptapType) {
253
253
  calloutBlock: "callout",
254
254
  queryBlock: "query",
255
255
  horizontalRule: "divider",
256
- fileBlock: "file"
256
+ fileBlock: "file",
257
+ linkPreview: "text"
257
258
  };
258
259
  return MAP[tiptapType] ?? "text";
259
260
  }
@@ -395,6 +396,130 @@ function extractTextFromNode(node) {
395
396
  if (!content) return "";
396
397
  return content.map(extractTextFromNode).join("");
397
398
  }
399
+ function extractInlineMarkdown(node) {
400
+ if (typeof node.text === "string") {
401
+ const marks = node.marks ?? [];
402
+ let text = node.text;
403
+ const linkMark = marks.find((m) => m.type === "link");
404
+ if (linkMark) {
405
+ const href = linkMark.attrs?.href ?? "";
406
+ return `[${text}](${href})`;
407
+ }
408
+ for (const mark of marks) {
409
+ if (mark.type === "bold") text = `**${text}**`;
410
+ else if (mark.type === "italic") text = `*${text}*`;
411
+ else if (mark.type === "code") text = `\`${text}\``;
412
+ else if (mark.type === "strike") text = `~~${text}~~`;
413
+ }
414
+ return text;
415
+ }
416
+ const content = node.content;
417
+ if (!content) return "";
418
+ return content.map(extractInlineMarkdown).join("");
419
+ }
420
+ function tiptapNodeToMarkdown(node) {
421
+ const type = node.type;
422
+ const attrs = node.attrs ?? {};
423
+ const content = node.content ?? [];
424
+ const lines = [];
425
+ switch (type) {
426
+ case "heading": {
427
+ const level = attrs.level ?? 1;
428
+ lines.push(`${"#".repeat(level)} ${extractInlineMarkdown({ content })}`);
429
+ break;
430
+ }
431
+ case "paragraph": {
432
+ lines.push(extractInlineMarkdown({ content }));
433
+ break;
434
+ }
435
+ case "taskList": {
436
+ for (const child of content) {
437
+ const childAttrs = child.attrs ?? {};
438
+ const checked = childAttrs.checked ? "x" : " ";
439
+ const text = extractInlineMarkdown(child);
440
+ lines.push(`- [${checked}] ${text}`);
441
+ }
442
+ break;
443
+ }
444
+ case "taskItem": {
445
+ const checked = attrs.checked ? "x" : " ";
446
+ lines.push(`- [${checked}] ${extractInlineMarkdown({ content })}`);
447
+ break;
448
+ }
449
+ case "bulletList": {
450
+ for (const child of content) {
451
+ const text = extractInlineMarkdown(child);
452
+ lines.push(`- ${text}`);
453
+ }
454
+ break;
455
+ }
456
+ case "orderedList": {
457
+ content.forEach((child, i) => {
458
+ const text = extractInlineMarkdown(child);
459
+ lines.push(`${i + 1}. ${text}`);
460
+ });
461
+ break;
462
+ }
463
+ case "codeBlock": {
464
+ const lang = attrs.language ?? "";
465
+ lines.push("```" + lang, extractTextFromNode(node), "```");
466
+ break;
467
+ }
468
+ case "mermaidBlock": {
469
+ lines.push("```mermaid", extractTextFromNode(node), "```");
470
+ break;
471
+ }
472
+ case "mathBlock": {
473
+ lines.push("$$", extractTextFromNode(node), "$$");
474
+ break;
475
+ }
476
+ case "calloutBlock": {
477
+ const variant = attrs.variant ?? "info";
478
+ const text = extractInlineMarkdown({ content });
479
+ lines.push(`> [!${variant}]`, ...text.split("\n").map((l) => `> ${l}`));
480
+ break;
481
+ }
482
+ case "queryBlock": {
483
+ const text = extractTextFromNode(node).trim();
484
+ lines.push(`> [!query]`, `> ${text}`);
485
+ break;
486
+ }
487
+ case "blockquote": {
488
+ const text = extractInlineMarkdown({ content });
489
+ lines.push(...text.split("\n").map((l) => `> ${l}`));
490
+ break;
491
+ }
492
+ case "horizontalRule": {
493
+ lines.push("---");
494
+ break;
495
+ }
496
+ case "image": {
497
+ const src = attrs.src ?? "";
498
+ const alt = attrs.alt ?? "";
499
+ lines.push(`![${alt}](${src})`);
500
+ break;
501
+ }
502
+ case "linkPreview": {
503
+ const url = attrs.url ?? "";
504
+ lines.push(`> [!embed]`, `> ${url}`);
505
+ break;
506
+ }
507
+ case "fileBlock": {
508
+ const src = attrs.src ?? "";
509
+ const filename = attrs.filename ?? "file";
510
+ const filesize = attrs.filesize ?? 0;
511
+ const filetype = attrs.filetype ?? "";
512
+ lines.push(`> [!file]`, `> [${filename}](${src})`, `> ${filetype} ${filesize}`);
513
+ break;
514
+ }
515
+ default: {
516
+ const text = extractTextFromNode(node);
517
+ if (text.trim()) lines.push(text);
518
+ break;
519
+ }
520
+ }
521
+ return lines;
522
+ }
398
523
  async function exportNoteAsJson(client, noteId) {
399
524
  const { data: note } = await client.from("notes").select("*").eq("id", noteId).single();
400
525
  const { data: blocks } = await client.from("blocks").select("*").eq("note_id", noteId).is("deleted_at", null).order("position");
@@ -408,53 +533,255 @@ async function exportNoteAsMarkdown(client, noteId) {
408
533
  const lines = [`# ${title}`, ""];
409
534
  for (const block of blocks) {
410
535
  const tiptap = block.metadata.tiptap;
411
- const type = tiptap?.type ?? block.type;
412
- const attrs = tiptap?.attrs ?? {};
413
- switch (type) {
414
- case "heading": {
415
- const level = attrs.level ?? 1;
416
- lines.push(`${"#".repeat(level)} ${block.content}`);
417
- break;
536
+ if (tiptap) {
537
+ lines.push(...tiptapNodeToMarkdown(tiptap), "");
538
+ } else {
539
+ if (block.content.trim()) lines.push(block.content, "");
540
+ }
541
+ }
542
+ return lines.join("\n");
543
+ }
544
+ function markdownToTiptap(md) {
545
+ const lines = md.split("\n");
546
+ const nodes = [];
547
+ let i = 0;
548
+ while (i < lines.length) {
549
+ const line = lines[i];
550
+ if (line.match(/^#{1,4}\s/)) {
551
+ const match = line.match(/^(#{1,4})\s(.*)$/);
552
+ if (match) {
553
+ nodes.push({
554
+ type: "heading",
555
+ attrs: { level: match[1].length },
556
+ content: parseInline(match[2])
557
+ });
558
+ }
559
+ i++;
560
+ continue;
561
+ }
562
+ if (line.match(/^```mermaid\s*$/)) {
563
+ const mermaidLines = [];
564
+ i++;
565
+ while (i < lines.length && !lines[i].match(/^```\s*$/)) {
566
+ mermaidLines.push(lines[i]);
567
+ i++;
418
568
  }
419
- case "taskList": {
420
- const children = tiptap?.content ?? [];
421
- for (const child of children) {
422
- const childAttrs = child.attrs ?? {};
423
- const checked = childAttrs.checked ? "x" : " ";
424
- const text = extractTextFromNode(child);
425
- lines.push(`- [${checked}] ${text}`);
569
+ i++;
570
+ nodes.push({
571
+ type: "mermaidBlock",
572
+ content: [{ type: "text", text: mermaidLines.join("\n") }]
573
+ });
574
+ continue;
575
+ }
576
+ if (line.match(/^```/)) {
577
+ const langMatch = line.match(/^```(\w*)$/);
578
+ const language = langMatch?.[1] || "plaintext";
579
+ const codeLines = [];
580
+ i++;
581
+ while (i < lines.length && !lines[i].match(/^```\s*$/)) {
582
+ codeLines.push(lines[i]);
583
+ i++;
584
+ }
585
+ i++;
586
+ nodes.push({
587
+ type: "codeBlock",
588
+ attrs: { language },
589
+ content: [{ type: "text", text: codeLines.join("\n") }]
590
+ });
591
+ continue;
592
+ }
593
+ if (line.match(/^\$\$\s*$/)) {
594
+ const mathLines = [];
595
+ i++;
596
+ while (i < lines.length && !lines[i].match(/^\$\$\s*$/)) {
597
+ mathLines.push(lines[i]);
598
+ i++;
599
+ }
600
+ i++;
601
+ nodes.push({
602
+ type: "mathBlock",
603
+ content: [{ type: "text", text: mathLines.join("\n") }]
604
+ });
605
+ continue;
606
+ }
607
+ if (line.match(/^>\s*\[!(\w+)\]\s*$/)) {
608
+ const variantMatch = line.match(/^>\s*\[!(\w+)\]\s*$/);
609
+ const variant = variantMatch?.[1] ?? "info";
610
+ if (variant === "query") {
611
+ const queryLines = [];
612
+ i++;
613
+ while (i < lines.length && lines[i].match(/^>\s/)) {
614
+ queryLines.push(lines[i].replace(/^>\s?/, ""));
615
+ i++;
426
616
  }
427
- break;
617
+ nodes.push({
618
+ type: "queryBlock",
619
+ content: [{ type: "text", text: queryLines.join("\n") }]
620
+ });
621
+ continue;
622
+ }
623
+ if (variant === "embed") {
624
+ i++;
625
+ const embedUrl = lines[i]?.replace(/^>\s?/, "").trim() ?? "";
626
+ i++;
627
+ nodes.push({
628
+ type: "linkPreview",
629
+ attrs: { url: embedUrl }
630
+ });
631
+ continue;
428
632
  }
429
- case "taskItem": {
430
- const checked = attrs.checked ? "x" : " ";
431
- lines.push(`- [${checked}] ${block.content}`);
432
- break;
633
+ if (variant === "file") {
634
+ i++;
635
+ const linkLine = lines[i]?.replace(/^>\s?/, "") ?? "";
636
+ const linkMatch = linkLine.match(/^\[(.+?)\]\((.+?)\)$/);
637
+ i++;
638
+ const metaLine = lines[i]?.replace(/^>\s?/, "") ?? "";
639
+ const metaParts = metaLine.split(" ");
640
+ i++;
641
+ nodes.push({
642
+ type: "fileBlock",
643
+ attrs: {
644
+ filename: linkMatch?.[1] ?? "file",
645
+ src: linkMatch?.[2] ?? "",
646
+ filetype: metaParts[0] ?? "",
647
+ filesize: parseInt(metaParts[1] ?? "0", 10) || 0
648
+ }
649
+ });
650
+ continue;
433
651
  }
434
- case "codeBlock": {
435
- const lang = attrs.language ?? "";
436
- lines.push("```" + lang, block.content, "```");
437
- break;
652
+ const calloutLines = [];
653
+ i++;
654
+ while (i < lines.length && lines[i].match(/^>\s/)) {
655
+ calloutLines.push(lines[i].replace(/^>\s?/, ""));
656
+ i++;
438
657
  }
439
- case "bulletList":
440
- lines.push(`- ${block.content}`);
441
- break;
442
- case "orderedList":
443
- lines.push(`1. ${block.content}`);
444
- break;
445
- case "blockquote":
446
- lines.push(`> ${block.content}`);
447
- break;
448
- case "horizontalRule":
449
- lines.push("---");
450
- break;
451
- default:
452
- lines.push(block.content);
453
- break;
454
- }
455
- lines.push("");
658
+ nodes.push({
659
+ type: "calloutBlock",
660
+ attrs: { variant },
661
+ content: [{ type: "paragraph", content: parseInline(calloutLines.join("\n")) }]
662
+ });
663
+ continue;
664
+ }
665
+ if (line.match(/^>\s/)) {
666
+ const quoteLines = [];
667
+ while (i < lines.length && lines[i].match(/^>\s?/)) {
668
+ quoteLines.push(lines[i].replace(/^>\s?/, ""));
669
+ i++;
670
+ }
671
+ nodes.push({
672
+ type: "blockquote",
673
+ content: [{ type: "paragraph", content: parseInline(quoteLines.join("\n")) }]
674
+ });
675
+ continue;
676
+ }
677
+ if (line.match(/^---\s*$/)) {
678
+ nodes.push({ type: "horizontalRule" });
679
+ i++;
680
+ continue;
681
+ }
682
+ if (line.match(/^!\[.*?\]\(.*?\)$/)) {
683
+ const imgMatch = line.match(/^!\[(.*?)\]\((.*?)\)$/);
684
+ if (imgMatch) {
685
+ nodes.push({
686
+ type: "image",
687
+ attrs: { src: imgMatch[2], alt: imgMatch[1] }
688
+ });
689
+ }
690
+ i++;
691
+ continue;
692
+ }
693
+ if (line.match(/^[-*]\s\[[ x]\]\s/)) {
694
+ const taskItems = [];
695
+ while (i < lines.length && lines[i].match(/^[-*]\s\[[ x]\]\s/)) {
696
+ const m = lines[i].match(/^[-*]\s\[([ x])\]\s(.*)$/);
697
+ if (m) {
698
+ taskItems.push({
699
+ type: "taskItem",
700
+ attrs: { checked: m[1] === "x" },
701
+ content: [{ type: "paragraph", content: parseInline(m[2]) }]
702
+ });
703
+ }
704
+ i++;
705
+ }
706
+ nodes.push({ type: "taskList", content: taskItems });
707
+ continue;
708
+ }
709
+ if (line.match(/^[-*]\s/)) {
710
+ const items = [];
711
+ while (i < lines.length && lines[i].match(/^[-*]\s/)) {
712
+ const text = lines[i].replace(/^[-*]\s/, "");
713
+ items.push({
714
+ type: "listItem",
715
+ content: [{ type: "paragraph", content: parseInline(text) }]
716
+ });
717
+ i++;
718
+ }
719
+ nodes.push({ type: "bulletList", content: items });
720
+ continue;
721
+ }
722
+ if (line.match(/^\d+\.\s/)) {
723
+ const items = [];
724
+ while (i < lines.length && lines[i].match(/^\d+\.\s/)) {
725
+ const text = lines[i].replace(/^\d+\.\s/, "");
726
+ items.push({
727
+ type: "listItem",
728
+ content: [{ type: "paragraph", content: parseInline(text) }]
729
+ });
730
+ i++;
731
+ }
732
+ nodes.push({ type: "orderedList", content: items });
733
+ continue;
734
+ }
735
+ if (line.trim() === "") {
736
+ i++;
737
+ continue;
738
+ }
739
+ const paraLines = [];
740
+ while (i < lines.length && lines[i].trim() !== "" && !lines[i].match(/^#{1,4}\s/) && !lines[i].match(/^```/) && !lines[i].match(/^\$\$/) && !lines[i].match(/^---\s*$/) && !lines[i].match(/^[-*]\s/) && !lines[i].match(/^\d+\.\s/) && !lines[i].match(/^>\s/) && !lines[i].match(/^!\[/)) {
741
+ paraLines.push(lines[i]);
742
+ i++;
743
+ }
744
+ nodes.push({
745
+ type: "paragraph",
746
+ content: parseInline(paraLines.join("\n"))
747
+ });
456
748
  }
457
- return lines.join("\n");
749
+ if (nodes.length === 0) {
750
+ nodes.push({ type: "paragraph" });
751
+ }
752
+ return { type: "doc", content: nodes };
753
+ }
754
+ function parseInline(text) {
755
+ if (!text) return [];
756
+ const nodes = [];
757
+ const regex = /(\*\*(.+?)\*\*|\*(.+?)\*|`(.+?)`|~~(.+?)~~|\[\[(.+?)\]\]|#([a-zA-Z][a-zA-Z0-9_/-]*)|\[([^\]]+?)\]\(([^)]+?)\))/g;
758
+ let lastIndex = 0;
759
+ let match;
760
+ while ((match = regex.exec(text)) !== null) {
761
+ if (match.index > lastIndex) {
762
+ nodes.push({ type: "text", text: text.slice(lastIndex, match.index) });
763
+ }
764
+ if (match[2]) {
765
+ nodes.push({ type: "text", text: match[2], marks: [{ type: "bold" }] });
766
+ } else if (match[3]) {
767
+ nodes.push({ type: "text", text: match[3], marks: [{ type: "italic" }] });
768
+ } else if (match[4]) {
769
+ nodes.push({ type: "text", text: match[4], marks: [{ type: "code" }] });
770
+ } else if (match[5]) {
771
+ nodes.push({ type: "text", text: match[5], marks: [{ type: "strike" }] });
772
+ } else if (match[6]) {
773
+ nodes.push({ type: "text", text: `[[${match[6]}]]` });
774
+ } else if (match[7]) {
775
+ nodes.push({ type: "text", text: `#${match[7]}` });
776
+ } else if (match[8] && match[9]) {
777
+ nodes.push({ type: "text", text: match[8], marks: [{ type: "link", attrs: { href: match[9], target: "_blank" } }] });
778
+ }
779
+ lastIndex = match.index + match[0].length;
780
+ }
781
+ if (lastIndex < text.length) {
782
+ nodes.push({ type: "text", text: text.slice(lastIndex) });
783
+ }
784
+ return nodes.length > 0 ? nodes : [{ type: "text", text: text || " " }];
458
785
  }
459
786
  var VERTEX_VERSION = "0.1.0";
460
787
 
@@ -474,6 +801,7 @@ export {
474
801
  executeQuery,
475
802
  exportNoteAsJson,
476
803
  exportNoteAsMarkdown,
804
+ markdownToTiptap,
477
805
  VERTEX_VERSION
478
806
  };
479
- //# sourceMappingURL=chunk-4QLCD6TZ.js.map
807
+ //# sourceMappingURL=chunk-WM6QVD53.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../core/src/client.ts","../../core/src/auth.ts","../../core/src/storage.ts","../../core/src/notes.ts","../../core/src/tags.ts","../../core/src/links.ts","../../core/src/blocks.ts","../../core/src/snapshots.ts","../../core/src/search.ts","../../core/src/graph.ts","../../core/src/templates.ts","../../core/src/export.ts","../../core/src/md-to-tiptap.ts","../../core/src/index.ts"],"sourcesContent":["import { createClient, type SupabaseClient } from \"@supabase/supabase-js\";\n\nexport type { SupabaseClient };\n\nlet defaultClient: SupabaseClient | null = null;\n\nexport function createSupabaseClient(\n url: string,\n anonKey: string,\n): SupabaseClient {\n return createClient(url, anonKey, {\n auth: {\n autoRefreshToken: true,\n persistSession: true,\n },\n });\n}\n\nexport function initSupabaseClient(url: string, anonKey: string): void {\n defaultClient = createSupabaseClient(url, anonKey);\n}\n\nexport function getSupabaseClient(): SupabaseClient {\n if (!defaultClient) {\n throw new Error(\n \"Supabase client not initialized. Call initSupabaseClient() first.\",\n );\n }\n return defaultClient;\n}\n","import type { SupabaseClient, User, Session } from \"@supabase/supabase-js\";\nimport type { Profile } from \"./types\";\n\nexport type { User, Session };\n\nexport type OAuthProvider = \"google\" | \"github\";\n\nexport async function signInWithOAuth(\n client: SupabaseClient,\n provider: OAuthProvider,\n redirectTo?: string,\n) {\n return client.auth.signInWithOAuth({\n provider,\n options: { redirectTo },\n });\n}\n\nexport async function signInWithEmail(\n client: SupabaseClient,\n email: string,\n password: string,\n) {\n return client.auth.signInWithPassword({ email, password });\n}\n\nexport async function signUpWithEmail(\n client: SupabaseClient,\n email: string,\n password: string,\n) {\n return client.auth.signUp({ email, password });\n}\n\nexport async function signOut(client: SupabaseClient) {\n return client.auth.signOut();\n}\n\nexport async function getUser(client: SupabaseClient) {\n return client.auth.getUser();\n}\n\nexport async function getSession(client: SupabaseClient) {\n return client.auth.getSession();\n}\n\nexport async function getProfile(\n client: SupabaseClient,\n userId: string,\n): Promise<Profile | null> {\n const { data, error } = await client\n .from(\"profiles\")\n .select(\"*\")\n .eq(\"id\", userId)\n .maybeSingle();\n\n if (error) return null;\n return data as Profile;\n}\n\nexport function onAuthStateChange(\n client: SupabaseClient,\n callback: (event: string, session: unknown) => void,\n) {\n return client.auth.onAuthStateChange(callback);\n}\n","import type { SupabaseClient } from \"@supabase/supabase-js\";\n\nexport const DEFAULT_STORAGE_CAP = 50 * 1024 * 1024;\n\nexport async function getStorageInfo(\n client: SupabaseClient,\n userId: string,\n): Promise<{ used: number; cap: number }> {\n const { data, error } = await client\n .from(\"profiles\")\n .select(\"storage_used, storage_cap\")\n .eq(\"id\", userId)\n .maybeSingle();\n if (error || !data) return { used: 0, cap: DEFAULT_STORAGE_CAP };\n return {\n used: (data.storage_used as number) ?? 0,\n cap: (data.storage_cap as number) ?? DEFAULT_STORAGE_CAP,\n };\n}\n\nexport async function getStorageUsed(\n client: SupabaseClient,\n userId: string,\n): Promise<number> {\n const { used } = await getStorageInfo(client, userId);\n return used;\n}\n\nexport async function getStorageCap(\n client: SupabaseClient,\n userId: string,\n): Promise<number> {\n const { cap } = await getStorageInfo(client, userId);\n return cap;\n}\n\nexport async function checkStorageCap(\n client: SupabaseClient,\n userId: string,\n fileSize: number,\n): Promise<{ allowed: boolean; used: number; cap: number }> {\n const { used, cap } = await getStorageInfo(client, userId);\n return { allowed: used + fileSize <= cap, used, cap };\n}\n\nexport async function incrementStorageUsed(\n client: SupabaseClient,\n userId: string,\n bytes: number,\n): Promise<void> {\n const used = await getStorageUsed(client, userId);\n await client\n .from(\"profiles\")\n .update({ storage_used: used + bytes })\n .eq(\"id\", userId);\n}\n\nexport async function decrementStorageUsed(\n client: SupabaseClient,\n userId: string,\n bytes: number,\n): Promise<void> {\n const used = await getStorageUsed(client, userId);\n await client\n .from(\"profiles\")\n .update({ storage_used: Math.max(0, used - bytes) })\n .eq(\"id\", userId);\n}\n\nexport function formatFileSize(bytes: number): string {\n if (bytes === 0) return \"0 B\";\n if (bytes < 1024) return `${bytes} B`;\n if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;\n if (bytes < 1024 * 1024 * 1024) return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;\n return `${(bytes / (1024 * 1024 * 1024)).toFixed(1)} GB`;\n}\n","import type { SupabaseClient } from \"@supabase/supabase-js\";\nimport type { Note, NoteType } from \"./types\";\nimport { decrementStorageUsed } from \"./storage\";\n\nexport type FileCleanupFn = (urls: Array<{ src: string; filesize: number }>) => Promise<void>;\n\nexport interface CreateNoteParams {\n user_id: string;\n title?: string;\n slug?: string;\n note_type?: NoteType;\n daily_date?: string;\n}\n\nasync function uniqueTitle(\n client: SupabaseClient,\n userId: string,\n title: string,\n excludeNoteId?: string,\n): Promise<string> {\n const { data } = await client\n .from(\"notes\")\n .select(\"title\")\n .eq(\"user_id\", userId)\n .is(\"deleted_at\", null);\n\n const existing = new Set(\n ((data ?? []) as Array<{ title: string }>)\n .filter(() => true)\n .map((n) => n.title),\n );\n\n if (excludeNoteId) {\n const { data: self } = await client\n .from(\"notes\")\n .select(\"title\")\n .eq(\"id\", excludeNoteId)\n .single();\n if (self) existing.delete((self as { title: string }).title);\n }\n\n if (!existing.has(title)) return title;\n\n let counter = 1;\n while (existing.has(`${title}(${counter})`)) counter++;\n return `${title}(${counter})`;\n}\n\nexport async function createNote(\n client: SupabaseClient,\n params: CreateNoteParams,\n): Promise<Note> {\n const title = await uniqueTitle(client, params.user_id, params.title ?? \"Untitled\");\n const { data, error } = await client\n .from(\"notes\")\n .insert({\n user_id: params.user_id,\n title,\n slug: params.slug ?? null,\n note_type: params.note_type ?? \"regular\",\n daily_date: params.daily_date ?? null,\n })\n .select()\n .single();\n\n if (error) throw error;\n return data as Note;\n}\n\nexport async function getNote(\n client: SupabaseClient,\n noteId: string,\n): Promise<Note | null> {\n const { data, error } = await client\n .from(\"notes\")\n .select(\"*\")\n .eq(\"id\", noteId)\n .is(\"deleted_at\", null)\n .single();\n\n if (error) return null;\n return data as Note;\n}\n\nexport async function updateNote(\n client: SupabaseClient,\n noteId: string,\n updates: Partial<Pick<Note, \"title\" | \"slug\" | \"is_pinned\">>,\n userId?: string,\n): Promise<Note> {\n const payload = { ...updates };\n if (payload.title && userId) {\n payload.title = await uniqueTitle(client, userId, payload.title, noteId);\n }\n const { data, error } = await client\n .from(\"notes\")\n .update(payload)\n .eq(\"id\", noteId)\n .select()\n .single();\n\n if (error) throw error;\n return data as Note;\n}\n\nexport async function softDeleteNote(\n client: SupabaseClient,\n noteId: string,\n): Promise<void> {\n const { error } = await client\n .from(\"notes\")\n .update({ deleted_at: new Date().toISOString() })\n .eq(\"id\", noteId);\n\n if (error) throw error;\n}\n\nexport async function restoreNote(\n client: SupabaseClient,\n noteId: string,\n): Promise<void> {\n const { error } = await client\n .from(\"notes\")\n .update({ deleted_at: null })\n .eq(\"id\", noteId);\n\n if (error) throw error;\n}\n\nexport async function hardDeleteNote(\n client: SupabaseClient,\n noteId: string,\n onFilesRemoved?: FileCleanupFn,\n): Promise<void> {\n const { data: blocks } = await client\n .from(\"blocks\")\n .select(\"type, metadata, user_id\")\n .eq(\"note_id\", noteId);\n\n const fileUrls: Array<{ src: string; filesize: number }> = [];\n let userId: string | null = null;\n\n for (const b of (blocks ?? []) as Array<{ type: string; metadata: Record<string, unknown>; user_id: string }>) {\n if (!userId) userId = b.user_id;\n const tiptap = b.metadata?.tiptap as Record<string, unknown> | undefined;\n const attrs = (tiptap?.attrs ?? {}) as Record<string, unknown>;\n const src = attrs.src as string | undefined;\n if (src && (b.type === \"file\" || b.type === \"image\") && !src.startsWith(\"data:\")) {\n fileUrls.push({ src, filesize: (attrs.filesize as number) ?? 0 });\n }\n }\n\n for (const file of fileUrls) {\n try {\n const parsed = new URL(file.src);\n if (parsed.pathname.includes(\"/storage/v1/object/public/\")) {\n const pathParts = parsed.pathname.split(\"/storage/v1/object/public/\");\n if (pathParts.length >= 2) {\n const fullPath = decodeURIComponent(pathParts[1]);\n const slashIdx = fullPath.indexOf(\"/\");\n if (slashIdx !== -1) {\n await client.storage.from(fullPath.substring(0, slashIdx)).remove([fullPath.substring(slashIdx + 1)]);\n }\n }\n }\n if (userId && file.filesize > 0) {\n await decrementStorageUsed(client, userId, file.filesize).catch(() => {});\n }\n } catch {\n // best-effort\n }\n }\n\n if (fileUrls.length > 0 && onFilesRemoved) {\n await onFilesRemoved(fileUrls).catch(() => {});\n }\n\n const { error } = await client\n .from(\"notes\")\n .delete()\n .eq(\"id\", noteId);\n\n if (error) throw error;\n\n if (userId) {\n await cleanupOrphanedTags(client, userId);\n }\n}\n\nasync function cleanupOrphanedTags(client: SupabaseClient, userId: string): Promise<void> {\n try {\n const { data: tags } = await client\n .from(\"tags\")\n .select(\"id\")\n .eq(\"user_id\", userId);\n\n if (!tags || tags.length === 0) return;\n\n for (const tag of tags) {\n const { count: blockCount } = await client\n .from(\"block_tags\")\n .select(\"*\", { count: \"exact\", head: true })\n .eq(\"tag_id\", tag.id);\n\n const { count: noteCount } = await client\n .from(\"note_tags\")\n .select(\"*\", { count: \"exact\", head: true })\n .eq(\"tag_id\", tag.id);\n\n if ((blockCount ?? 0) === 0 && (noteCount ?? 0) === 0) {\n await client.from(\"tag_edges\").delete().or(`parent_id.eq.${tag.id},child_id.eq.${tag.id}`);\n await client.from(\"tags\").delete().eq(\"id\", tag.id);\n }\n }\n } catch {\n // best-effort\n }\n}\n\nexport async function emptyTrash(\n client: SupabaseClient,\n userId: string,\n): Promise<number> {\n const { data } = await client\n .from(\"notes\")\n .select(\"id\")\n .eq(\"user_id\", userId)\n .not(\"deleted_at\", \"is\", null);\n\n if (!data || data.length === 0) return 0;\n\n const ids = (data as Array<{ id: string }>).map((n) => n.id);\n const { error } = await client\n .from(\"notes\")\n .delete()\n .in(\"id\", ids);\n\n if (error) throw error;\n return ids.length;\n}\n\nexport interface ListNotesParams {\n user_id: string;\n note_type?: NoteType;\n is_pinned?: boolean;\n include_deleted?: boolean;\n limit?: number;\n offset?: number;\n}\n\nexport async function listNotes(\n client: SupabaseClient,\n params: ListNotesParams,\n): Promise<Note[]> {\n let query = client\n .from(\"notes\")\n .select(\"*\")\n .eq(\"user_id\", params.user_id)\n .order(\"updated_at\", { ascending: false });\n\n if (!params.include_deleted) {\n query = query.is(\"deleted_at\", null);\n }\n if (params.note_type) {\n query = query.eq(\"note_type\", params.note_type);\n }\n if (params.is_pinned !== undefined) {\n query = query.eq(\"is_pinned\", params.is_pinned);\n }\n if (params.limit) {\n query = query.limit(params.limit);\n }\n if (params.offset) {\n query = query.range(params.offset, params.offset + (params.limit ?? 50) - 1);\n }\n\n const { data, error } = await query;\n if (error) throw error;\n return (data ?? []) as Note[];\n}\n\nexport async function getOrCreateDailyNote(\n client: SupabaseClient,\n userId: string,\n date: string,\n): Promise<Note> {\n const { data: existing } = await client\n .from(\"notes\")\n .select(\"*\")\n .eq(\"user_id\", userId)\n .eq(\"note_type\", \"daily\")\n .eq(\"daily_date\", date)\n .single();\n\n if (existing) return existing as Note;\n\n const dateObj = new Date(date + \"T00:00:00\");\n const title = dateObj.toLocaleDateString(\"en-US\", {\n year: \"numeric\",\n month: \"long\",\n day: \"numeric\",\n });\n\n return createNote(client, {\n user_id: userId,\n title,\n slug: date,\n note_type: \"daily\",\n daily_date: date,\n });\n}\n","import type { SupabaseClient } from \"@supabase/supabase-js\";\nimport type { Tag, TagEdge } from \"./types\";\n\nexport async function createTag(\n client: SupabaseClient,\n userId: string,\n name: string,\n color?: string,\n): Promise<Tag> {\n const { data, error } = await client\n .from(\"tags\")\n .insert({ user_id: userId, name: name.toLowerCase(), color: color ?? null })\n .select()\n .single();\n\n if (error) throw error;\n return data as Tag;\n}\n\nexport async function getOrCreateTag(\n client: SupabaseClient,\n userId: string,\n name: string,\n color?: string,\n): Promise<Tag> {\n const normalized = name.toLowerCase();\n const { data: existing } = await client\n .from(\"tags\")\n .select(\"*\")\n .eq(\"user_id\", userId)\n .eq(\"name\", normalized)\n .single();\n\n if (existing) return existing as Tag;\n return createTag(client, userId, normalized, color);\n}\n\nexport async function getUserTags(\n client: SupabaseClient,\n userId: string,\n): Promise<Tag[]> {\n const { data, error } = await client\n .from(\"tags\")\n .select(\"*\")\n .eq(\"user_id\", userId)\n .order(\"name\");\n\n if (error) throw error;\n return (data ?? []) as Tag[];\n}\n\nexport async function updateTag(\n client: SupabaseClient,\n tagId: string,\n updates: Partial<Pick<Tag, \"name\" | \"color\">>,\n): Promise<Tag> {\n const payload: Record<string, unknown> = {};\n if (updates.name !== undefined) payload.name = updates.name.toLowerCase();\n if (updates.color !== undefined) payload.color = updates.color;\n\n const { data, error } = await client\n .from(\"tags\")\n .update(payload)\n .eq(\"id\", tagId)\n .select()\n .single();\n\n if (error) throw error;\n return data as Tag;\n}\n\nexport async function deleteTag(\n client: SupabaseClient,\n tagId: string,\n): Promise<void> {\n const { error } = await client.from(\"tags\").delete().eq(\"id\", tagId);\n if (error) throw error;\n}\n\nexport async function addTagEdge(\n client: SupabaseClient,\n userId: string,\n parentId: string,\n childId: string,\n): Promise<TagEdge> {\n const { data, error } = await client\n .from(\"tag_edges\")\n .insert({ parent_id: parentId, child_id: childId, user_id: userId })\n .select()\n .single();\n\n if (error) throw error;\n return data as TagEdge;\n}\n\nexport async function removeTagEdge(\n client: SupabaseClient,\n parentId: string,\n childId: string,\n): Promise<void> {\n const { error } = await client\n .from(\"tag_edges\")\n .delete()\n .eq(\"parent_id\", parentId)\n .eq(\"child_id\", childId);\n\n if (error) throw error;\n}\n\nexport async function getTagParents(\n client: SupabaseClient,\n tagId: string,\n): Promise<Tag[]> {\n const { data, error } = await client\n .from(\"tag_edges\")\n .select(\"parent_id\")\n .eq(\"child_id\", tagId);\n\n if (error) throw error;\n if (!data || data.length === 0) return [];\n\n const parentIds = data.map((e) => (e as TagEdge).parent_id);\n const { data: tags, error: tagErr } = await client\n .from(\"tags\")\n .select(\"*\")\n .in(\"id\", parentIds);\n\n if (tagErr) throw tagErr;\n return (tags ?? []) as Tag[];\n}\n\nexport async function getTagChildren(\n client: SupabaseClient,\n tagId: string,\n): Promise<Tag[]> {\n const { data, error } = await client\n .from(\"tag_edges\")\n .select(\"child_id\")\n .eq(\"parent_id\", tagId);\n\n if (error) throw error;\n if (!data || data.length === 0) return [];\n\n const childIds = data.map((e) => (e as TagEdge).child_id);\n const { data: tags, error: tagErr } = await client\n .from(\"tags\")\n .select(\"*\")\n .in(\"id\", childIds);\n\n if (tagErr) throw tagErr;\n return (tags ?? []) as Tag[];\n}\n\nexport async function getTagDescendants(\n client: SupabaseClient,\n tagId: string,\n): Promise<string[]> {\n const { data, error } = await client.rpc(\"get_tag_descendants\", {\n root_tag_id: tagId,\n });\n\n if (error) throw error;\n return ((data ?? []) as Array<{ tag_id: string }>).map((r) => r.tag_id);\n}\n\nexport async function addBlockTag(\n client: SupabaseClient,\n blockId: string,\n tagId: string,\n): Promise<void> {\n const { error } = await client\n .from(\"block_tags\")\n .upsert({ block_id: blockId, tag_id: tagId }, { onConflict: \"block_id,tag_id\" });\n\n if (error) throw error;\n}\n\nexport async function removeBlockTag(\n client: SupabaseClient,\n blockId: string,\n tagId: string,\n): Promise<void> {\n const { error } = await client\n .from(\"block_tags\")\n .delete()\n .eq(\"block_id\", blockId)\n .eq(\"tag_id\", tagId);\n\n if (error) throw error;\n}\n\nexport async function getBlocksByTag(\n client: SupabaseClient,\n userId: string,\n tagId: string,\n includeDescendants = true,\n): Promise<string[]> {\n let tagIds: string[];\n if (includeDescendants) {\n tagIds = await getTagDescendants(client, tagId);\n } else {\n tagIds = [tagId];\n }\n\n const { data, error } = await client\n .from(\"block_tags\")\n .select(\"block_id, blocks!inner(user_id)\")\n .in(\"tag_id\", tagIds);\n\n if (error) throw error;\n return ((data ?? []) as Array<{ block_id: string }>).map((r) => r.block_id);\n}\n","import type { SupabaseClient } from \"@supabase/supabase-js\";\nimport type { Link, LinkTargetType, BacklinkResult, Block } from \"./types\";\n\nexport async function createLink(\n client: SupabaseClient,\n userId: string,\n sourceBlockId: string,\n targetType: LinkTargetType,\n targetId: string,\n): Promise<Link> {\n const { data, error } = await client\n .from(\"links\")\n .insert({\n user_id: userId,\n source_block_id: sourceBlockId,\n target_type: targetType,\n target_id: targetId,\n })\n .select()\n .single();\n\n if (error) throw error;\n return data as Link;\n}\n\nexport async function deleteLinksForBlock(\n client: SupabaseClient,\n sourceBlockId: string,\n): Promise<void> {\n const { error } = await client\n .from(\"links\")\n .delete()\n .eq(\"source_block_id\", sourceBlockId);\n\n if (error) throw error;\n}\n\nexport async function getBacklinksForNote(\n client: SupabaseClient,\n noteId: string,\n): Promise<BacklinkResult[]> {\n const { data, error } = await client\n .from(\"links\")\n .select(\"source_block_id, blocks!inner(id, note_id, content, type, position, metadata, user_id, created_at, updated_at, deleted_at)\")\n .eq(\"target_type\", \"note\")\n .eq(\"target_id\", noteId);\n\n if (error) throw error;\n if (!data || data.length === 0) return [];\n\n const blockRows = data as unknown as Array<{ source_block_id: string; blocks: Record<string, unknown> }>;\n const noteIds = [...new Set(blockRows.map((r) => r.blocks.note_id as string))];\n\n const { data: notes } = await client\n .from(\"notes\")\n .select(\"id, title\")\n .in(\"id\", noteIds);\n\n const noteMap = new Map((notes ?? []).map((n: Record<string, unknown>) => [n.id as string, n.title as string]));\n\n return blockRows.map((r) => ({\n source_block: r.blocks as unknown as Block,\n source_note_title: noteMap.get(r.blocks.note_id as string) ?? \"Untitled\",\n }));\n}\n\nexport async function syncLinksForNote(\n client: SupabaseClient,\n userId: string,\n noteId: string,\n wikiLinks: Array<{ blockId?: string; targetNoteTitle: string }>,\n): Promise<void> {\n const { data: existingBlocks } = await client\n .from(\"blocks\")\n .select(\"id\")\n .eq(\"note_id\", noteId);\n\n if (existingBlocks) {\n const blockIds = existingBlocks.map((b: Record<string, unknown>) => b.id as string);\n if (blockIds.length > 0) {\n await client\n .from(\"links\")\n .delete()\n .in(\"source_block_id\", blockIds);\n }\n }\n\n if (wikiLinks.length === 0) return;\n\n const titles = [...new Set(wikiLinks.map((l) => l.targetNoteTitle))];\n const { data: targetNotes } = await client\n .from(\"notes\")\n .select(\"id, title\")\n .eq(\"user_id\", userId)\n .in(\"title\", titles);\n\n if (!targetNotes || targetNotes.length === 0) return;\n\n const titleToId = new Map(\n (targetNotes as Array<{ id: string; title: string }>).map((n) => [n.title, n.id]),\n );\n\n const newBlocks = await client\n .from(\"blocks\")\n .select(\"id\")\n .eq(\"note_id\", noteId)\n .order(\"position\");\n\n if (!newBlocks.data) return;\n const firstBlockId = (newBlocks.data[0] as Record<string, unknown>)?.id as string | undefined;\n\n const linksToInsert = wikiLinks\n .map((l) => {\n const targetId = titleToId.get(l.targetNoteTitle);\n if (!targetId) return null;\n return {\n user_id: userId,\n source_block_id: l.blockId ?? firstBlockId,\n target_type: \"note\" as LinkTargetType,\n target_id: targetId,\n };\n })\n .filter((l): l is NonNullable<typeof l> => l !== null && l.source_block_id !== undefined);\n\n if (linksToInsert.length > 0) {\n await client.from(\"links\").insert(linksToInsert);\n }\n}\n","import type { SupabaseClient } from \"@supabase/supabase-js\";\nimport type { Block, BlockType, BlockMetadata } from \"./types\";\nimport { getOrCreateTag, addTagEdge, addBlockTag } from \"./tags\";\nimport { syncLinksForNote } from \"./links\";\n\nexport interface CreateBlockParams {\n note_id: string;\n user_id: string;\n type?: BlockType;\n content?: string;\n position: number;\n metadata?: BlockMetadata;\n}\n\nexport async function createBlock(\n client: SupabaseClient,\n params: CreateBlockParams,\n): Promise<Block> {\n const { data, error } = await client\n .from(\"blocks\")\n .insert({\n note_id: params.note_id,\n user_id: params.user_id,\n type: params.type ?? \"text\",\n content: params.content ?? \"\",\n position: params.position,\n metadata: params.metadata ?? {},\n })\n .select()\n .single();\n\n if (error) throw error;\n return data as Block;\n}\n\nexport async function getBlocksForNote(\n client: SupabaseClient,\n noteId: string,\n): Promise<Block[]> {\n const { data, error } = await client\n .from(\"blocks\")\n .select(\"*\")\n .eq(\"note_id\", noteId)\n .is(\"deleted_at\", null)\n .order(\"position\", { ascending: true });\n\n if (error) throw error;\n return (data ?? []) as Block[];\n}\n\nexport async function updateBlock(\n client: SupabaseClient,\n blockId: string,\n updates: Partial<Pick<Block, \"content\" | \"type\" | \"position\" | \"metadata\">>,\n): Promise<Block> {\n const { data, error } = await client\n .from(\"blocks\")\n .update(updates)\n .eq(\"id\", blockId)\n .select()\n .single();\n\n if (error) throw error;\n return data as Block;\n}\n\nexport async function deleteBlock(\n client: SupabaseClient,\n blockId: string,\n): Promise<void> {\n const { error } = await client\n .from(\"blocks\")\n .update({ deleted_at: new Date().toISOString() })\n .eq(\"id\", blockId);\n\n if (error) throw error;\n}\n\nexport async function upsertBlocks(\n client: SupabaseClient,\n blocks: Array<{\n id?: string;\n note_id: string;\n user_id: string;\n type: BlockType;\n content: string;\n position: number;\n metadata: BlockMetadata;\n }>,\n): Promise<Block[]> {\n const { data, error } = await client\n .from(\"blocks\")\n .upsert(blocks, { onConflict: \"id\" })\n .select();\n\n if (error) throw error;\n return (data ?? []) as Block[];\n}\n\nconst saveLocks = new Map<string, Promise<void>>();\n\nexport async function saveNoteContent(\n client: SupabaseClient,\n noteId: string,\n userId: string,\n tiptapJson: Record<string, unknown>,\n): Promise<void> {\n const existing = saveLocks.get(noteId);\n const doSave = async () => {\n if (existing) await existing.catch(() => {});\n await _saveNoteContentInner(client, noteId, userId, tiptapJson);\n };\n const promise = doSave();\n saveLocks.set(noteId, promise);\n try {\n await promise;\n } finally {\n if (saveLocks.get(noteId) === promise) saveLocks.delete(noteId);\n }\n}\n\nasync function _saveNoteContentInner(\n client: SupabaseClient,\n noteId: string,\n userId: string,\n tiptapJson: Record<string, unknown>,\n): Promise<void> {\n const nodes = tiptapJson.content as Array<Record<string, unknown>> | undefined;\n if (!nodes) return;\n\n const blocksToInsert = nodes.map((node, index) => ({\n note_id: noteId,\n user_id: userId,\n type: mapTiptapTypeToBlockType(node.type as string),\n content: extractPlainText(node),\n position: (index + 1) * 1.0,\n metadata: { tiptap: node },\n }));\n\n if (blocksToInsert.length === 0) return;\n\n const { error } = await client\n .from(\"blocks\")\n .delete()\n .eq(\"note_id\", noteId);\n\n if (error) throw error;\n\n const { error: insertError } = await client\n .from(\"blocks\")\n .insert(blocksToInsert);\n\n if (insertError) throw insertError;\n\n const { data: insertedBlocks } = await client\n .from(\"blocks\")\n .select(\"id, content, type\")\n .eq(\"note_id\", noteId)\n .order(\"position\");\n\n const blockRows = (insertedBlocks ?? []) as Array<{ id: string; content: string; type: string }>;\n\n await client.from(\"block_tags\").delete().in(\"block_id\", blockRows.map((b) => b.id));\n await client.from(\"note_tags\").delete().eq(\"note_id\", noteId);\n\n const noteTagIds = new Set<string>();\n\n const SKIP_TAG_TYPES = new Set([\"code\", \"mermaid\", \"math\", \"image\", \"divider\", \"chart\", \"file\"]);\n\n for (const block of blockRows) {\n if (SKIP_TAG_TYPES.has(block.type)) continue;\n\n const leafTags = extractLeafTags(block.content);\n for (const tagName of leafTags) {\n const tag = await getOrCreateTag(client, userId, tagName);\n await addBlockTag(client, block.id, tag.id).catch(() => {});\n noteTagIds.add(tag.id);\n }\n\n const scopedTags = extractScopedTags(block.content);\n for (const { parent, child } of scopedTags) {\n const parentTag = await getOrCreateTag(client, userId, parent);\n const childTag = await getOrCreateTag(client, userId, child);\n await addTagEdge(client, userId, parentTag.id, childTag.id).catch(() => {});\n }\n }\n\n for (const tagId of noteTagIds) {\n await client\n .from(\"note_tags\")\n .upsert({ note_id: noteId, tag_id: tagId }, { onConflict: \"note_id,tag_id\" });\n }\n\n const fullText = blockRows.map((b) => b.content).join(\" \");\n\n const wikiLinkTitles = extractWikiLinks(fullText);\n if (wikiLinkTitles.length > 0) {\n await syncLinksForNote(client, userId, noteId, wikiLinkTitles.map((t) => ({ targetNoteTitle: t })));\n }\n}\n\nfunction mapTiptapTypeToBlockType(tiptapType: string): BlockType {\n const MAP: Record<string, BlockType> = {\n paragraph: \"text\",\n heading: \"heading\",\n codeBlock: \"code\",\n taskList: \"todo\",\n taskItem: \"todo\",\n blockquote: \"text\",\n bulletList: \"text\",\n orderedList: \"text\",\n image: \"image\",\n mermaidBlock: \"mermaid\",\n mathBlock: \"math\",\n calloutBlock: \"callout\",\n queryBlock: \"query\",\n horizontalRule: \"divider\",\n fileBlock: \"file\",\n linkPreview: \"text\",\n };\n return MAP[tiptapType] ?? \"text\";\n}\n\nfunction extractPlainText(node: Record<string, unknown>): string {\n if (typeof node.text === \"string\") return node.text;\n const content = node.content as Array<Record<string, unknown>> | undefined;\n if (!content) return \"\";\n return content.map(extractPlainText).join(\"\");\n}\n\nfunction extractLeafTags(text: string): string[] {\n const matches = text.match(/#([a-zA-Z][a-zA-Z0-9_-]*(?:\\/[a-zA-Z][a-zA-Z0-9_-]*)*)/g);\n if (!matches) return [];\n const tags = new Set<string>();\n for (const m of matches) {\n const full = m.slice(1).toLowerCase();\n if (full.includes(\"/\")) {\n const parts = full.split(\"/\");\n tags.add(parts[parts.length - 1]);\n } else {\n tags.add(full);\n }\n }\n return [...tags];\n}\n\nfunction extractScopedTags(text: string): Array<{ parent: string; child: string }> {\n const matches = text.match(/#([a-zA-Z][a-zA-Z0-9_-]*(?:\\/[a-zA-Z][a-zA-Z0-9_-]*)+)/g);\n if (!matches) return [];\n const edges: Array<{ parent: string; child: string }> = [];\n for (const m of matches) {\n const parts = m.slice(1).toLowerCase().split(\"/\");\n for (let i = 0; i < parts.length - 1; i++) {\n edges.push({ parent: parts[i], child: parts[i + 1] });\n }\n }\n return edges;\n}\n\nfunction extractWikiLinks(text: string): string[] {\n const matches = text.match(/\\[\\[([^\\]]+)\\]\\]/g);\n if (!matches) return [];\n return [...new Set(matches.map((m) => m.slice(2, -2)))];\n}\n","import type { SupabaseClient } from \"@supabase/supabase-js\";\nimport type { Snapshot } from \"./types\";\n\nfunction generateHash(): string {\n const chars = \"0123456789abcdef\";\n let hash = \"\";\n for (let i = 0; i < 8; i++) {\n hash += chars[Math.floor(Math.random() * chars.length)];\n }\n return hash;\n}\n\nexport async function createSnapshot(\n client: SupabaseClient,\n noteId: string,\n userId: string,\n content: Record<string, unknown>,\n message?: string,\n): Promise<Snapshot | null> {\n const latest = await getLatestSnapshot(client, noteId);\n if (latest && JSON.stringify(latest.content) === JSON.stringify(content)) {\n return null;\n }\n\n const { data, error } = await client\n .from(\"snapshots\")\n .insert({\n note_id: noteId,\n user_id: userId,\n content,\n hash: generateHash(),\n message: message ?? null,\n })\n .select()\n .single();\n\n if (error) throw error;\n return data as Snapshot;\n}\n\nexport async function listSnapshots(\n client: SupabaseClient,\n noteId: string,\n limit = 50,\n): Promise<Snapshot[]> {\n const { data, error } = await client\n .from(\"snapshots\")\n .select(\"*\")\n .eq(\"note_id\", noteId)\n .order(\"created_at\", { ascending: false })\n .limit(limit);\n\n if (error) throw error;\n return (data ?? []) as Snapshot[];\n}\n\nexport async function getSnapshot(\n client: SupabaseClient,\n snapshotId: string,\n): Promise<Snapshot | null> {\n const { data, error } = await client\n .from(\"snapshots\")\n .select(\"*\")\n .eq(\"id\", snapshotId)\n .single();\n\n if (error) return null;\n return data as Snapshot;\n}\n\nexport async function getLatestSnapshot(\n client: SupabaseClient,\n noteId: string,\n): Promise<Snapshot | null> {\n const { data, error } = await client\n .from(\"snapshots\")\n .select(\"*\")\n .eq(\"note_id\", noteId)\n .order(\"created_at\", { ascending: false })\n .limit(1)\n .single();\n\n if (error) return null;\n return data as Snapshot;\n}\n\nexport interface DiffResult {\n added: string[];\n removed: string[];\n unchanged: string[];\n}\n\nexport function diffSnapshots(\n older: Record<string, unknown>,\n newer: Record<string, unknown>,\n): DiffResult {\n const olderBlocks = extractBlockTexts(older);\n const newerBlocks = extractBlockTexts(newer);\n\n const olderSet = new Set(olderBlocks);\n const newerSet = new Set(newerBlocks);\n\n const added = newerBlocks.filter((b) => !olderSet.has(b));\n const removed = olderBlocks.filter((b) => !newerSet.has(b));\n const unchanged = newerBlocks.filter((b) => olderSet.has(b));\n\n return { added, removed, unchanged };\n}\n\nfunction extractBlockTexts(tiptapJson: Record<string, unknown>): string[] {\n const content = tiptapJson.content as Array<Record<string, unknown>> | undefined;\n if (!content) return [];\n return content.map((node) => {\n return extractText(node).trim();\n }).filter(Boolean);\n}\n\nfunction extractText(node: Record<string, unknown>): string {\n if (typeof node.text === \"string\") return node.text;\n const children = node.content as Array<Record<string, unknown>> | undefined;\n if (!children) return \"\";\n return children.map(extractText).join(\"\");\n}\n","import type { SupabaseClient } from \"@supabase/supabase-js\";\nimport type { Block, Note, BlockType } from \"./types\";\nimport { getTagDescendants } from \"./tags\";\n\nexport interface SearchResult {\n block: Block;\n noteId: string;\n noteTitle: string;\n matchType: \"text\" | \"tag\" | \"type\";\n}\n\nexport async function fullTextSearch(\n client: SupabaseClient,\n userId: string,\n query: string,\n limit = 30,\n): Promise<SearchResult[]> {\n const { data, error } = await client\n .from(\"blocks\")\n .select(\"*, notes!inner(id, title)\")\n .eq(\"user_id\", userId)\n .is(\"deleted_at\", null)\n .textSearch(\"content\", query, { type: \"websearch\" })\n .limit(limit);\n\n if (error) throw error;\n\n return ((data ?? []) as Array<Record<string, unknown>>).map((row) => {\n const notes = row.notes as Record<string, unknown>;\n return {\n block: row as unknown as Block,\n noteId: notes.id as string,\n noteTitle: notes.title as string,\n matchType: \"text\" as const,\n };\n });\n}\n\nexport async function searchByTag(\n client: SupabaseClient,\n userId: string,\n tagName: string,\n includeDescendants = true,\n): Promise<SearchResult[]> {\n const { data: tags } = await client\n .from(\"tags\")\n .select(\"id\")\n .eq(\"user_id\", userId)\n .eq(\"name\", tagName.toLowerCase())\n .single();\n\n if (!tags) return [];\n const tagId = (tags as Record<string, string>).id;\n\n let tagIds: string[];\n if (includeDescendants) {\n tagIds = await getTagDescendants(client, tagId);\n } else {\n tagIds = [tagId];\n }\n\n const { data, error } = await client\n .from(\"block_tags\")\n .select(\"block_id, blocks!inner(*, notes!inner(id, title))\")\n .in(\"tag_id\", tagIds);\n\n if (error) throw error;\n\n return ((data ?? []) as Array<Record<string, unknown>>).map((row) => {\n const block = row.blocks as Record<string, unknown>;\n const notes = block.notes as Record<string, unknown>;\n return {\n block: block as unknown as Block,\n noteId: notes.id as string,\n noteTitle: notes.title as string,\n matchType: \"tag\" as const,\n };\n });\n}\n\nexport async function searchByType(\n client: SupabaseClient,\n userId: string,\n blockType: BlockType,\n limit = 50,\n): Promise<SearchResult[]> {\n const { data, error } = await client\n .from(\"blocks\")\n .select(\"*, notes!inner(id, title)\")\n .eq(\"user_id\", userId)\n .eq(\"type\", blockType)\n .is(\"deleted_at\", null)\n .limit(limit);\n\n if (error) throw error;\n\n return ((data ?? []) as Array<Record<string, unknown>>).map((row) => {\n const notes = row.notes as Record<string, unknown>;\n return {\n block: row as unknown as Block,\n noteId: notes.id as string,\n noteTitle: notes.title as string,\n matchType: \"type\" as const,\n };\n });\n}\n\nexport interface QueryFilter {\n text?: string;\n tag?: string;\n type?: BlockType;\n status?: \"open\" | \"done\";\n hasLink?: boolean;\n}\n\nexport function parseQuery(input: string): QueryFilter {\n const filter: QueryFilter = {};\n const parts = input.trim().split(/\\s+/);\n const textParts: string[] = [];\n\n for (const part of parts) {\n if (part.startsWith(\"#\")) {\n const raw = part.slice(1).toLowerCase();\n filter.tag = raw.includes(\"/\") ? raw.split(\"/\").pop()! : raw;\n } else if (part.startsWith(\"type:\")) {\n filter.type = part.slice(5) as BlockType;\n } else if (part.startsWith(\"status:\")) {\n filter.status = part.slice(7) as \"open\" | \"done\";\n } else if (part === \"has:link\") {\n filter.hasLink = true;\n } else {\n textParts.push(part);\n }\n }\n\n if (textParts.length > 0) {\n filter.text = textParts.join(\" \");\n }\n\n return filter;\n}\n\nexport async function executeQuery(\n client: SupabaseClient,\n userId: string,\n input: string,\n limit = 30,\n): Promise<SearchResult[]> {\n const filter = parseQuery(input);\n let results: SearchResult[] = [];\n\n if (filter.tag) {\n results = await searchByTag(client, userId, filter.tag);\n } else if (filter.type) {\n results = await searchByType(client, userId, filter.type, limit);\n } else if (filter.text) {\n results = await fullTextSearch(client, userId, filter.text, limit);\n }\n\n if (filter.status && results.length > 0) {\n const isDone = filter.status === \"done\";\n results = results.filter((r) => {\n const meta = r.block.metadata as Record<string, unknown>;\n if (meta.status === filter.status) return true;\n const json = JSON.stringify(meta);\n if (isDone) return json.includes('\"checked\":true');\n return json.includes('\"checked\":false') || (json.includes('\"taskItem\"') && !json.includes('\"checked\":true'));\n });\n }\n\n return results;\n}\n","import type { SupabaseClient } from \"@supabase/supabase-js\";\n\nexport interface GraphNode {\n id: string;\n label: string;\n type: \"note\" | \"tag\";\n color?: string;\n}\n\nexport interface GraphEdge {\n source: string;\n target: string;\n type: \"link\" | \"tag\";\n}\n\nexport interface GraphData {\n nodes: GraphNode[];\n edges: GraphEdge[];\n}\n\nexport async function getGraphData(\n client: SupabaseClient,\n userId: string,\n): Promise<GraphData> {\n const nodes: GraphNode[] = [];\n const edges: GraphEdge[] = [];\n\n const { data: notes } = await client\n .from(\"notes\")\n .select(\"id, title\")\n .eq(\"user_id\", userId)\n .is(\"deleted_at\", null);\n\n for (const n of (notes ?? []) as Array<{ id: string; title: string }>) {\n nodes.push({ id: n.id, label: n.title, type: \"note\" });\n }\n\n const { data: links } = await client\n .from(\"links\")\n .select(\"source_block_id, target_id, target_type, blocks!inner(note_id)\")\n .eq(\"user_id\", userId)\n .eq(\"target_type\", \"note\");\n\n for (const l of (links ?? []) as unknown as Array<{ target_id: string; blocks: { note_id: string } }>) {\n const sourceNoteId = l.blocks.note_id;\n const targetNoteId = l.target_id;\n if (sourceNoteId && targetNoteId && sourceNoteId !== targetNoteId) {\n edges.push({ source: sourceNoteId, target: targetNoteId, type: \"link\" });\n }\n }\n\n const { data: tags } = await client\n .from(\"tags\")\n .select(\"id, name, color\")\n .eq(\"user_id\", userId);\n\n for (const t of (tags ?? []) as Array<{ id: string; name: string; color: string | null }>) {\n nodes.push({ id: `tag-${t.id}`, label: `#${t.name}`, type: \"tag\", color: t.color ?? undefined });\n }\n\n const { data: noteTags } = await client\n .from(\"note_tags\")\n .select(\"note_id, tag_id\");\n\n for (const nt of (noteTags ?? []) as Array<{ note_id: string; tag_id: string }>) {\n edges.push({ source: nt.note_id, target: `tag-${nt.tag_id}`, type: \"tag\" });\n }\n\n const { data: tagEdges } = await client\n .from(\"tag_edges\")\n .select(\"parent_id, child_id\")\n .eq(\"user_id\", userId);\n\n for (const te of (tagEdges ?? []) as Array<{ parent_id: string; child_id: string }>) {\n edges.push({ source: `tag-${te.parent_id}`, target: `tag-${te.child_id}`, type: \"tag\" });\n }\n\n return { nodes, edges };\n}\n","export interface NoteTemplate {\n id: string;\n name: string;\n content: Record<string, unknown>;\n}\n\nexport const NOTE_TEMPLATES: NoteTemplate[] = [\n {\n id: \"blank\",\n name: \"Blank Note\",\n content: { type: \"doc\", content: [{ type: \"paragraph\" }] },\n },\n {\n id: \"meeting\",\n name: \"Meeting Notes\",\n content: {\n type: \"doc\",\n content: [\n { type: \"heading\", attrs: { level: 1 }, content: [{ type: \"text\", text: \"Meeting Notes\" }] },\n { type: \"heading\", attrs: { level: 2 }, content: [{ type: \"text\", text: \"Attendees\" }] },\n { type: \"paragraph\", content: [{ type: \"text\", text: \"- \" }] },\n { type: \"heading\", attrs: { level: 2 }, content: [{ type: \"text\", text: \"Agenda\" }] },\n { type: \"paragraph\", content: [{ type: \"text\", text: \"1. \" }] },\n { type: \"heading\", attrs: { level: 2 }, content: [{ type: \"text\", text: \"Discussion\" }] },\n { type: \"paragraph\" },\n { type: \"heading\", attrs: { level: 2 }, content: [{ type: \"text\", text: \"Action Items\" }] },\n { type: \"taskList\", content: [{ type: \"taskItem\", attrs: { checked: false }, content: [{ type: \"paragraph\" }] }] },\n ],\n },\n },\n {\n id: \"daily-standup\",\n name: \"Daily Standup\",\n content: {\n type: \"doc\",\n content: [\n { type: \"heading\", attrs: { level: 1 }, content: [{ type: \"text\", text: \"Daily Standup\" }] },\n { type: \"heading\", attrs: { level: 2 }, content: [{ type: \"text\", text: \"Yesterday\" }] },\n { type: \"taskList\", content: [{ type: \"taskItem\", attrs: { checked: true }, content: [{ type: \"paragraph\" }] }] },\n { type: \"heading\", attrs: { level: 2 }, content: [{ type: \"text\", text: \"Today\" }] },\n { type: \"taskList\", content: [{ type: \"taskItem\", attrs: { checked: false }, content: [{ type: \"paragraph\" }] }] },\n { type: \"heading\", attrs: { level: 2 }, content: [{ type: \"text\", text: \"Blockers\" }] },\n { type: \"paragraph\" },\n ],\n },\n },\n {\n id: \"project\",\n name: \"Project Plan\",\n content: {\n type: \"doc\",\n content: [\n { type: \"heading\", attrs: { level: 1 }, content: [{ type: \"text\", text: \"Project Name\" }] },\n { type: \"heading\", attrs: { level: 2 }, content: [{ type: \"text\", text: \"Overview\" }] },\n { type: \"paragraph\" },\n { type: \"heading\", attrs: { level: 2 }, content: [{ type: \"text\", text: \"Goals\" }] },\n { type: \"paragraph\", content: [{ type: \"text\", text: \"- \" }] },\n { type: \"heading\", attrs: { level: 2 }, content: [{ type: \"text\", text: \"Timeline\" }] },\n { type: \"paragraph\" },\n { type: \"heading\", attrs: { level: 2 }, content: [{ type: \"text\", text: \"Tasks\" }] },\n { type: \"taskList\", content: [{ type: \"taskItem\", attrs: { checked: false }, content: [{ type: \"paragraph\" }] }] },\n { type: \"heading\", attrs: { level: 2 }, content: [{ type: \"text\", text: \"Notes\" }] },\n { type: \"paragraph\" },\n ],\n },\n },\n];\n","import type { SupabaseClient } from \"@supabase/supabase-js\";\nimport type { Note } from \"./types\";\n\nfunction extractTextFromNode(node: Record<string, unknown>): string {\n if (typeof node.text === \"string\") return node.text;\n const content = node.content as Array<Record<string, unknown>> | undefined;\n if (!content) return \"\";\n return content.map(extractTextFromNode).join(\"\");\n}\n\nfunction extractInlineMarkdown(node: Record<string, unknown>): string {\n if (typeof node.text === \"string\") {\n const marks = (node.marks ?? []) as Array<{ type: string; attrs?: Record<string, unknown> }>;\n let text = node.text;\n const linkMark = marks.find((m) => m.type === \"link\");\n if (linkMark) {\n const href = (linkMark.attrs?.href as string) ?? \"\";\n return `[${text}](${href})`;\n }\n for (const mark of marks) {\n if (mark.type === \"bold\") text = `**${text}**`;\n else if (mark.type === \"italic\") text = `*${text}*`;\n else if (mark.type === \"code\") text = `\\`${text}\\``;\n else if (mark.type === \"strike\") text = `~~${text}~~`;\n }\n return text;\n }\n const content = node.content as Array<Record<string, unknown>> | undefined;\n if (!content) return \"\";\n return content.map(extractInlineMarkdown).join(\"\");\n}\n\nfunction tiptapNodeToMarkdown(node: Record<string, unknown>): string[] {\n const type = node.type as string;\n const attrs = (node.attrs ?? {}) as Record<string, unknown>;\n const content = (node.content ?? []) as Array<Record<string, unknown>>;\n const lines: string[] = [];\n\n switch (type) {\n case \"heading\": {\n const level = (attrs.level as number) ?? 1;\n lines.push(`${\"#\".repeat(level)} ${extractInlineMarkdown({ content } as Record<string, unknown>)}`);\n break;\n }\n case \"paragraph\": {\n lines.push(extractInlineMarkdown({ content } as Record<string, unknown>));\n break;\n }\n case \"taskList\": {\n for (const child of content) {\n const childAttrs = (child.attrs ?? {}) as Record<string, unknown>;\n const checked = childAttrs.checked ? \"x\" : \" \";\n const text = extractInlineMarkdown(child);\n lines.push(`- [${checked}] ${text}`);\n }\n break;\n }\n case \"taskItem\": {\n const checked = attrs.checked ? \"x\" : \" \";\n lines.push(`- [${checked}] ${extractInlineMarkdown({ content } as Record<string, unknown>)}`);\n break;\n }\n case \"bulletList\": {\n for (const child of content) {\n const text = extractInlineMarkdown(child);\n lines.push(`- ${text}`);\n }\n break;\n }\n case \"orderedList\": {\n content.forEach((child, i) => {\n const text = extractInlineMarkdown(child);\n lines.push(`${i + 1}. ${text}`);\n });\n break;\n }\n case \"codeBlock\": {\n const lang = (attrs.language as string) ?? \"\";\n lines.push(\"```\" + lang, extractTextFromNode(node), \"```\");\n break;\n }\n case \"mermaidBlock\": {\n lines.push(\"```mermaid\", extractTextFromNode(node), \"```\");\n break;\n }\n case \"mathBlock\": {\n lines.push(\"$$\", extractTextFromNode(node), \"$$\");\n break;\n }\n case \"calloutBlock\": {\n const variant = (attrs.variant as string) ?? \"info\";\n const text = extractInlineMarkdown({ content } as Record<string, unknown>);\n lines.push(`> [!${variant}]`, ...text.split(\"\\n\").map((l) => `> ${l}`));\n break;\n }\n case \"queryBlock\": {\n const text = extractTextFromNode(node).trim();\n lines.push(`> [!query]`, `> ${text}`);\n break;\n }\n case \"blockquote\": {\n const text = extractInlineMarkdown({ content } as Record<string, unknown>);\n lines.push(...text.split(\"\\n\").map((l) => `> ${l}`));\n break;\n }\n case \"horizontalRule\": {\n lines.push(\"---\");\n break;\n }\n case \"image\": {\n const src = attrs.src as string ?? \"\";\n const alt = (attrs.alt as string) ?? \"\";\n lines.push(`![${alt}](${src})`);\n break;\n }\n case \"linkPreview\": {\n const url = attrs.url as string ?? \"\";\n lines.push(`> [!embed]`, `> ${url}`);\n break;\n }\n case \"fileBlock\": {\n const src = attrs.src as string ?? \"\";\n const filename = (attrs.filename as string) ?? \"file\";\n const filesize = (attrs.filesize as number) ?? 0;\n const filetype = (attrs.filetype as string) ?? \"\";\n lines.push(`> [!file]`, `> [${filename}](${src})`, `> ${filetype} ${filesize}`);\n break;\n }\n default: {\n const text = extractTextFromNode(node);\n if (text.trim()) lines.push(text);\n break;\n }\n }\n\n return lines;\n}\n\nexport async function exportNoteAsJson(\n client: SupabaseClient,\n noteId: string,\n): Promise<string> {\n const { data: note } = await client\n .from(\"notes\")\n .select(\"*\")\n .eq(\"id\", noteId)\n .single();\n\n const { data: blocks } = await client\n .from(\"blocks\")\n .select(\"*\")\n .eq(\"note_id\", noteId)\n .is(\"deleted_at\", null)\n .order(\"position\");\n\n return JSON.stringify({ note, blocks }, null, 2);\n}\n\nexport async function exportNoteAsMarkdown(\n client: SupabaseClient,\n noteId: string,\n): Promise<string> {\n const { data: note } = await client\n .from(\"notes\")\n .select(\"title\")\n .eq(\"id\", noteId)\n .single();\n\n const { data: blocks } = await client\n .from(\"blocks\")\n .select(\"type, content, metadata\")\n .eq(\"note_id\", noteId)\n .is(\"deleted_at\", null)\n .order(\"position\");\n\n if (!blocks) return \"\";\n\n const title = (note as Record<string, string>)?.title ?? \"Untitled\";\n const lines: string[] = [`# ${title}`, \"\"];\n\n for (const block of blocks as Array<{ type: string; content: string; metadata: Record<string, unknown> }>) {\n const tiptap = block.metadata.tiptap as Record<string, unknown> | undefined;\n if (tiptap) {\n lines.push(...tiptapNodeToMarkdown(tiptap), \"\");\n } else {\n if (block.content.trim()) lines.push(block.content, \"\");\n }\n }\n\n return lines.join(\"\\n\");\n}\n","interface TiptapNode {\n type: string;\n attrs?: Record<string, unknown>;\n content?: TiptapNode[];\n text?: string;\n marks?: Array<{ type: string; attrs?: Record<string, unknown> }>;\n}\n\nexport function markdownToTiptap(md: string): Record<string, unknown> {\n const lines = md.split(\"\\n\");\n const nodes: TiptapNode[] = [];\n let i = 0;\n\n while (i < lines.length) {\n const line = lines[i];\n\n if (line.match(/^#{1,4}\\s/)) {\n const match = line.match(/^(#{1,4})\\s(.*)$/);\n if (match) {\n nodes.push({\n type: \"heading\",\n attrs: { level: match[1].length },\n content: parseInline(match[2]),\n });\n }\n i++;\n continue;\n }\n\n if (line.match(/^```mermaid\\s*$/)) {\n const mermaidLines: string[] = [];\n i++;\n while (i < lines.length && !lines[i].match(/^```\\s*$/)) {\n mermaidLines.push(lines[i]);\n i++;\n }\n i++;\n nodes.push({\n type: \"mermaidBlock\",\n content: [{ type: \"text\", text: mermaidLines.join(\"\\n\") }],\n });\n continue;\n }\n\n if (line.match(/^```/)) {\n const langMatch = line.match(/^```(\\w*)$/);\n const language = langMatch?.[1] || \"plaintext\";\n const codeLines: string[] = [];\n i++;\n while (i < lines.length && !lines[i].match(/^```\\s*$/)) {\n codeLines.push(lines[i]);\n i++;\n }\n i++;\n nodes.push({\n type: \"codeBlock\",\n attrs: { language },\n content: [{ type: \"text\", text: codeLines.join(\"\\n\") }],\n });\n continue;\n }\n\n if (line.match(/^\\$\\$\\s*$/)) {\n const mathLines: string[] = [];\n i++;\n while (i < lines.length && !lines[i].match(/^\\$\\$\\s*$/)) {\n mathLines.push(lines[i]);\n i++;\n }\n i++;\n nodes.push({\n type: \"mathBlock\",\n content: [{ type: \"text\", text: mathLines.join(\"\\n\") }],\n });\n continue;\n }\n\n if (line.match(/^>\\s*\\[!(\\w+)\\]\\s*$/)) {\n const variantMatch = line.match(/^>\\s*\\[!(\\w+)\\]\\s*$/);\n const variant = variantMatch?.[1] ?? \"info\";\n\n if (variant === \"query\") {\n const queryLines: string[] = [];\n i++;\n while (i < lines.length && lines[i].match(/^>\\s/)) {\n queryLines.push(lines[i].replace(/^>\\s?/, \"\"));\n i++;\n }\n nodes.push({\n type: \"queryBlock\",\n content: [{ type: \"text\", text: queryLines.join(\"\\n\") }],\n });\n continue;\n }\n\n if (variant === \"embed\") {\n i++;\n const embedUrl = lines[i]?.replace(/^>\\s?/, \"\").trim() ?? \"\";\n i++;\n nodes.push({\n type: \"linkPreview\",\n attrs: { url: embedUrl },\n });\n continue;\n }\n\n if (variant === \"file\") {\n i++;\n const linkLine = lines[i]?.replace(/^>\\s?/, \"\") ?? \"\";\n const linkMatch = linkLine.match(/^\\[(.+?)\\]\\((.+?)\\)$/);\n i++;\n const metaLine = lines[i]?.replace(/^>\\s?/, \"\") ?? \"\";\n const metaParts = metaLine.split(\" \");\n i++;\n nodes.push({\n type: \"fileBlock\",\n attrs: {\n filename: linkMatch?.[1] ?? \"file\",\n src: linkMatch?.[2] ?? \"\",\n filetype: metaParts[0] ?? \"\",\n filesize: parseInt(metaParts[1] ?? \"0\", 10) || 0,\n },\n });\n continue;\n }\n\n const calloutLines: string[] = [];\n i++;\n while (i < lines.length && lines[i].match(/^>\\s/)) {\n calloutLines.push(lines[i].replace(/^>\\s?/, \"\"));\n i++;\n }\n nodes.push({\n type: \"calloutBlock\",\n attrs: { variant },\n content: [{ type: \"paragraph\", content: parseInline(calloutLines.join(\"\\n\")) }],\n });\n continue;\n }\n\n if (line.match(/^>\\s/)) {\n const quoteLines: string[] = [];\n while (i < lines.length && lines[i].match(/^>\\s?/)) {\n quoteLines.push(lines[i].replace(/^>\\s?/, \"\"));\n i++;\n }\n nodes.push({\n type: \"blockquote\",\n content: [{ type: \"paragraph\", content: parseInline(quoteLines.join(\"\\n\")) }],\n });\n continue;\n }\n\n if (line.match(/^---\\s*$/)) {\n nodes.push({ type: \"horizontalRule\" });\n i++;\n continue;\n }\n\n if (line.match(/^!\\[.*?\\]\\(.*?\\)$/)) {\n const imgMatch = line.match(/^!\\[(.*?)\\]\\((.*?)\\)$/);\n if (imgMatch) {\n nodes.push({\n type: \"image\",\n attrs: { src: imgMatch[2], alt: imgMatch[1] },\n });\n }\n i++;\n continue;\n }\n\n if (line.match(/^[-*]\\s\\[[ x]\\]\\s/)) {\n const taskItems: TiptapNode[] = [];\n while (i < lines.length && lines[i].match(/^[-*]\\s\\[[ x]\\]\\s/)) {\n const m = lines[i].match(/^[-*]\\s\\[([ x])\\]\\s(.*)$/);\n if (m) {\n taskItems.push({\n type: \"taskItem\",\n attrs: { checked: m[1] === \"x\" },\n content: [{ type: \"paragraph\", content: parseInline(m[2]) }],\n });\n }\n i++;\n }\n nodes.push({ type: \"taskList\", content: taskItems });\n continue;\n }\n\n if (line.match(/^[-*]\\s/)) {\n const items: TiptapNode[] = [];\n while (i < lines.length && lines[i].match(/^[-*]\\s/)) {\n const text = lines[i].replace(/^[-*]\\s/, \"\");\n items.push({\n type: \"listItem\",\n content: [{ type: \"paragraph\", content: parseInline(text) }],\n });\n i++;\n }\n nodes.push({ type: \"bulletList\", content: items });\n continue;\n }\n\n if (line.match(/^\\d+\\.\\s/)) {\n const items: TiptapNode[] = [];\n while (i < lines.length && lines[i].match(/^\\d+\\.\\s/)) {\n const text = lines[i].replace(/^\\d+\\.\\s/, \"\");\n items.push({\n type: \"listItem\",\n content: [{ type: \"paragraph\", content: parseInline(text) }],\n });\n i++;\n }\n nodes.push({ type: \"orderedList\", content: items });\n continue;\n }\n\n if (line.trim() === \"\") {\n i++;\n continue;\n }\n\n const paraLines: string[] = [];\n while (\n i < lines.length &&\n lines[i].trim() !== \"\" &&\n !lines[i].match(/^#{1,4}\\s/) &&\n !lines[i].match(/^```/) &&\n !lines[i].match(/^\\$\\$/) &&\n !lines[i].match(/^---\\s*$/) &&\n !lines[i].match(/^[-*]\\s/) &&\n !lines[i].match(/^\\d+\\.\\s/) &&\n !lines[i].match(/^>\\s/) &&\n !lines[i].match(/^!\\[/)\n ) {\n paraLines.push(lines[i]);\n i++;\n }\n nodes.push({\n type: \"paragraph\",\n content: parseInline(paraLines.join(\"\\n\")),\n });\n }\n\n if (nodes.length === 0) {\n nodes.push({ type: \"paragraph\" });\n }\n\n return { type: \"doc\", content: nodes };\n}\n\nfunction parseInline(text: string): TiptapNode[] {\n if (!text) return [];\n\n const nodes: TiptapNode[] = [];\n const regex = /(\\*\\*(.+?)\\*\\*|\\*(.+?)\\*|`(.+?)`|~~(.+?)~~|\\[\\[(.+?)\\]\\]|#([a-zA-Z][a-zA-Z0-9_/-]*)|\\[([^\\]]+?)\\]\\(([^)]+?)\\))/g;\n let lastIndex = 0;\n let match: RegExpExecArray | null;\n\n while ((match = regex.exec(text)) !== null) {\n if (match.index > lastIndex) {\n nodes.push({ type: \"text\", text: text.slice(lastIndex, match.index) });\n }\n\n if (match[2]) {\n nodes.push({ type: \"text\", text: match[2], marks: [{ type: \"bold\" }] });\n } else if (match[3]) {\n nodes.push({ type: \"text\", text: match[3], marks: [{ type: \"italic\" }] });\n } else if (match[4]) {\n nodes.push({ type: \"text\", text: match[4], marks: [{ type: \"code\" }] });\n } else if (match[5]) {\n nodes.push({ type: \"text\", text: match[5], marks: [{ type: \"strike\" }] });\n } else if (match[6]) {\n nodes.push({ type: \"text\", text: `[[${match[6]}]]` });\n } else if (match[7]) {\n nodes.push({ type: \"text\", text: `#${match[7]}` });\n } else if (match[8] && match[9]) {\n nodes.push({ type: \"text\", text: match[8], marks: [{ type: \"link\", attrs: { href: match[9], target: \"_blank\" } }] });\n }\n\n lastIndex = match.index + match[0].length;\n }\n\n if (lastIndex < text.length) {\n nodes.push({ type: \"text\", text: text.slice(lastIndex) });\n }\n\n return nodes.length > 0 ? nodes : [{ type: \"text\", text: text || \" \" }];\n}\n","export const VERTEX_VERSION = \"0.1.0\";\n\nexport {\n createSupabaseClient,\n initSupabaseClient,\n getSupabaseClient,\n type SupabaseClient,\n} from \"./client\";\n\nexport type {\n NoteType,\n BlockType,\n LinkTargetType,\n Priority,\n TodoStatus,\n CalloutVariant,\n ChartType,\n Profile,\n UserPreferences,\n Note,\n Block,\n BlockMetadata,\n TodoMetadata,\n CodeMetadata,\n HeadingMetadata,\n ImageMetadata,\n FileMetadata,\n MermaidMetadata,\n ChartMetadata,\n CalloutMetadata,\n QueryMetadata,\n ScopeMetadata,\n Tag,\n TagEdge,\n BlockTag,\n NoteTag,\n Link,\n Snapshot,\n SrsCard,\n TagWithCounts,\n NoteWithTags,\n BlockWithTags,\n BacklinkResult,\n} from \"./types\";\n\nexport {\n signInWithOAuth,\n signInWithEmail,\n signUpWithEmail,\n signOut,\n getUser,\n getSession,\n getProfile,\n onAuthStateChange,\n type OAuthProvider,\n type User,\n type Session,\n} from \"./auth\";\n\nexport {\n createNote,\n getNote,\n updateNote,\n softDeleteNote,\n restoreNote,\n hardDeleteNote,\n emptyTrash,\n listNotes,\n getOrCreateDailyNote,\n type CreateNoteParams,\n type ListNotesParams,\n type FileCleanupFn,\n} from \"./notes\";\n\nexport {\n createBlock,\n getBlocksForNote,\n updateBlock,\n deleteBlock,\n upsertBlocks,\n saveNoteContent,\n type CreateBlockParams,\n} from \"./blocks\";\n\nexport {\n createTag,\n getOrCreateTag,\n getUserTags,\n updateTag,\n deleteTag,\n addTagEdge,\n removeTagEdge,\n getTagParents,\n getTagChildren,\n getTagDescendants,\n addBlockTag,\n removeBlockTag,\n getBlocksByTag,\n} from \"./tags\";\n\nexport {\n createLink,\n deleteLinksForBlock,\n getBacklinksForNote,\n syncLinksForNote,\n} from \"./links\";\n\nexport {\n createSnapshot,\n listSnapshots,\n getSnapshot,\n getLatestSnapshot,\n diffSnapshots,\n type DiffResult,\n} from \"./snapshots\";\n\nexport {\n fullTextSearch,\n searchByTag,\n searchByType,\n parseQuery,\n executeQuery,\n type SearchResult,\n type QueryFilter,\n} from \"./search\";\n\nexport {\n getGraphData,\n type GraphNode,\n type GraphEdge,\n type GraphData,\n} from \"./graph\";\n\nexport { NOTE_TEMPLATES, type NoteTemplate } from \"./templates\";\n\nexport {\n exportNoteAsJson,\n exportNoteAsMarkdown,\n} from \"./export\";\n\nexport { markdownToTiptap } from \"./md-to-tiptap\";\n\nexport {\n DEFAULT_STORAGE_CAP,\n getStorageInfo,\n getStorageUsed,\n getStorageCap,\n checkStorageCap,\n incrementStorageUsed,\n decrementStorageUsed,\n formatFileSize,\n} from \"./storage\";\n"],"mappings":"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","names":[]}