n8n-nodes-notion-advanced 1.1.31-beta → 1.2.0-beta

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.
@@ -9,5 +9,9 @@ export declare class NotionAITool implements INodeType {
9
9
  static createDatabaseEntry(executeFunctions: IExecuteFunctions, itemIndex: number): Promise<IDataObject>;
10
10
  static queryDatabase(executeFunctions: IExecuteFunctions, itemIndex: number): Promise<IDataObject>;
11
11
  static parseContentToBlocks(content: string): IDataObject[];
12
+ static processXmlTags(content: string, blocks: IDataObject[]): string;
13
+ static getCalloutEmoji(type: string): string;
14
+ static getCalloutColor(type: string): string;
15
+ static parseBasicMarkdown(text: string): IDataObject[];
12
16
  static parsePropertiesToUpdate(propertiesString: string): IDataObject;
13
17
  }
@@ -446,96 +446,523 @@ class NotionAITool {
446
446
  }
447
447
  static parseContentToBlocks(content) {
448
448
  const blocks = [];
449
- const lines = content.split('\n');
449
+ // Handle both actual newlines and escaped \n characters
450
+ const normalizedContent = content.replace(/\\n/g, '\n');
451
+ // First, process XML-like tags for reliable parsing
452
+ const processedContent = NotionAITool.processXmlTags(normalizedContent, blocks);
453
+ // Then process remaining content with traditional markdown patterns
454
+ const lines = processedContent.split('\n');
450
455
  for (let i = 0; i < lines.length; i++) {
451
- const line = lines[i].trim();
452
- if (!line)
456
+ const line = lines[i];
457
+ const trimmedLine = line.trim();
458
+ // Skip completely empty lines and XML placeholders
459
+ if (!trimmedLine || trimmedLine.startsWith('__XML_BLOCK_'))
453
460
  continue;
454
- // Parse different content types
455
- if (line.startsWith('# ')) {
461
+ // Traditional markdown patterns (for backwards compatibility)
462
+ if (trimmedLine.startsWith('# ')) {
456
463
  blocks.push({
457
- object: 'block',
458
464
  type: 'heading_1',
459
465
  heading_1: {
460
- rich_text: [(0, NotionUtils_1.createRichText)(line.substring(2))],
466
+ rich_text: [(0, NotionUtils_1.createRichText)(trimmedLine.substring(2).trim())],
461
467
  },
462
468
  });
463
469
  }
464
- else if (line.startsWith('## ')) {
470
+ else if (trimmedLine.startsWith('## ')) {
465
471
  blocks.push({
466
- object: 'block',
467
472
  type: 'heading_2',
468
473
  heading_2: {
469
- rich_text: [(0, NotionUtils_1.createRichText)(line.substring(3))],
474
+ rich_text: [(0, NotionUtils_1.createRichText)(trimmedLine.substring(3).trim())],
470
475
  },
471
476
  });
472
477
  }
473
- else if (line.startsWith('### ')) {
478
+ else if (trimmedLine.startsWith('### ')) {
474
479
  blocks.push({
475
- object: 'block',
476
480
  type: 'heading_3',
477
481
  heading_3: {
478
- rich_text: [(0, NotionUtils_1.createRichText)(line.substring(4))],
482
+ rich_text: [(0, NotionUtils_1.createRichText)(trimmedLine.substring(4).trim())],
479
483
  },
480
484
  });
481
485
  }
482
- else if (line.startsWith('- ') || line.startsWith('* ')) {
486
+ else if (trimmedLine === '---' || trimmedLine === '***') {
487
+ blocks.push({
488
+ type: 'divider',
489
+ divider: {},
490
+ });
491
+ }
492
+ else if (trimmedLine.includes('[!') && trimmedLine.startsWith('>')) {
493
+ // Callout blocks: > [!info] content
494
+ const calloutMatch = trimmedLine.match(/^>\s*\[!(\w+)\]\s*(.*)/i);
495
+ if (calloutMatch) {
496
+ const [, calloutType, text] = calloutMatch;
497
+ const emoji = NotionAITool.getCalloutEmoji(calloutType.toLowerCase());
498
+ const color = NotionAITool.getCalloutColor(calloutType.toLowerCase());
499
+ blocks.push({
500
+ type: 'callout',
501
+ callout: {
502
+ rich_text: NotionAITool.parseBasicMarkdown(text),
503
+ icon: { type: 'emoji', emoji },
504
+ color: color,
505
+ },
506
+ });
507
+ }
508
+ else {
509
+ blocks.push({
510
+ type: 'quote',
511
+ quote: {
512
+ rich_text: NotionAITool.parseBasicMarkdown(trimmedLine.substring(1).trim()),
513
+ },
514
+ });
515
+ }
516
+ }
517
+ else if (trimmedLine.startsWith('![') && trimmedLine.includes('](') && trimmedLine.endsWith(')')) {
518
+ // Image: ![alt text](url)
519
+ const match = trimmedLine.match(/^!\[(.*?)\]\((.*?)\)$/);
520
+ if (match) {
521
+ const [, altText, url] = match;
522
+ blocks.push({
523
+ type: 'image',
524
+ image: {
525
+ type: 'external',
526
+ external: { url },
527
+ caption: altText ? NotionAITool.parseBasicMarkdown(altText) : [],
528
+ },
529
+ });
530
+ }
531
+ }
532
+ else if (trimmedLine.startsWith('$$') && trimmedLine.endsWith('$$') && trimmedLine.length > 4) {
533
+ // Equation: $$equation$$
534
+ const equation = trimmedLine.substring(2, trimmedLine.length - 2).trim();
535
+ blocks.push({
536
+ type: 'equation',
537
+ equation: {
538
+ expression: equation,
539
+ },
540
+ });
541
+ }
542
+ else if ((trimmedLine.startsWith('http://') || trimmedLine.startsWith('https://')) && !trimmedLine.includes(' ')) {
543
+ // Check if it's a video URL for embed, otherwise bookmark
544
+ const videoPatterns = [
545
+ /(?:https?:\/\/)?(?:www\.)?(?:youtube\.com\/watch\?v=|youtu\.be\/)/i,
546
+ /(?:https?:\/\/)?(?:www\.)?(?:vimeo\.com\/)/i,
547
+ /(?:https?:\/\/)?(?:www\.)?(?:dailymotion\.com\/video\/)/i,
548
+ /(?:https?:\/\/)?(?:www\.)?(?:twitch\.tv\/)/i,
549
+ /(?:https?:\/\/)?(?:www\.)?(?:loom\.com\/share\/)/i,
550
+ /(?:https?:\/\/)?(?:www\.)?(?:figma\.com\/)/i,
551
+ /(?:https?:\/\/)?(?:www\.)?(?:miro\.com\/)/i,
552
+ /(?:https?:\/\/)?(?:codepen\.io\/)/i
553
+ ];
554
+ const isEmbeddableUrl = videoPatterns.some(pattern => pattern.test(trimmedLine));
555
+ if (isEmbeddableUrl) {
556
+ blocks.push({
557
+ type: 'embed',
558
+ embed: {
559
+ url: trimmedLine,
560
+ },
561
+ });
562
+ }
563
+ else {
564
+ blocks.push({
565
+ type: 'bookmark',
566
+ bookmark: {
567
+ url: trimmedLine,
568
+ },
569
+ });
570
+ }
571
+ }
572
+ else if (trimmedLine.startsWith('- [') && (trimmedLine.includes('[ ]') || trimmedLine.includes('[x]') || trimmedLine.includes('[X]'))) {
573
+ // To-do list items: - [ ] or - [x] or - [X]
574
+ const isChecked = trimmedLine.includes('[x]') || trimmedLine.includes('[X]');
575
+ const text = trimmedLine.replace(/^-\s*\[[ xX]\]\s*/, '').trim();
576
+ blocks.push({
577
+ type: 'to_do',
578
+ to_do: {
579
+ rich_text: NotionAITool.parseBasicMarkdown(text),
580
+ checked: isChecked,
581
+ },
582
+ });
583
+ }
584
+ else if (trimmedLine.startsWith('- ') && !trimmedLine.startsWith('- [')) {
585
+ // Bullet list items: - item (but not todos)
586
+ const listText = trimmedLine.substring(2).trim();
483
587
  blocks.push({
484
- object: 'block',
485
588
  type: 'bulleted_list_item',
486
589
  bulleted_list_item: {
487
- rich_text: [(0, NotionUtils_1.createRichText)(line.substring(2))],
590
+ rich_text: NotionAITool.parseBasicMarkdown(listText),
488
591
  },
489
592
  });
490
593
  }
491
- else if (line.match(/^\d+\. /)) {
594
+ else if (/^\d+\.\s/.test(trimmedLine)) {
595
+ // Numbered list items: 1. item
596
+ const listText = trimmedLine.replace(/^\d+\.\s/, '').trim();
492
597
  blocks.push({
493
- object: 'block',
494
598
  type: 'numbered_list_item',
495
599
  numbered_list_item: {
496
- rich_text: [(0, NotionUtils_1.createRichText)(line.replace(/^\d+\. /, ''))],
600
+ rich_text: NotionAITool.parseBasicMarkdown(listText),
497
601
  },
498
602
  });
499
603
  }
500
- else if (line.startsWith('> ')) {
604
+ else if (trimmedLine.startsWith('> ') && !trimmedLine.includes('[!')) {
605
+ // Quote block (but not callout)
501
606
  blocks.push({
502
- object: 'block',
503
607
  type: 'quote',
504
608
  quote: {
505
- rich_text: [(0, NotionUtils_1.createRichText)(line.substring(2))],
609
+ rich_text: NotionAITool.parseBasicMarkdown(trimmedLine.substring(2).trim()),
506
610
  },
507
611
  });
508
612
  }
509
- else if (line.startsWith('```')) {
613
+ else if (trimmedLine.startsWith('```')) {
510
614
  // Handle code blocks
615
+ const language = trimmedLine.substring(3).trim() || 'plain text';
511
616
  const codeLines = [];
512
617
  i++; // Skip the opening ```
618
+ // Collect all code lines until closing ```
513
619
  while (i < lines.length && !lines[i].trim().startsWith('```')) {
514
620
  codeLines.push(lines[i]);
515
621
  i++;
516
622
  }
517
623
  blocks.push({
518
- object: 'block',
519
624
  type: 'code',
520
625
  code: {
521
626
  rich_text: [(0, NotionUtils_1.createRichText)(codeLines.join('\n'))],
522
- language: 'plain text',
627
+ language: language === 'plain text' ? 'plain_text' : language,
523
628
  },
524
629
  });
525
630
  }
526
631
  else {
527
- // Regular paragraph
632
+ // Regular paragraph - handle basic markdown formatting
633
+ const richText = NotionAITool.parseBasicMarkdown(trimmedLine);
528
634
  blocks.push({
529
- object: 'block',
530
635
  type: 'paragraph',
531
636
  paragraph: {
532
- rich_text: [(0, NotionUtils_1.createRichText)(line)],
637
+ rich_text: richText,
533
638
  },
534
639
  });
535
640
  }
536
641
  }
537
642
  return blocks;
538
643
  }
644
+ // New XML-like tag processing function
645
+ static processXmlTags(content, blocks) {
646
+ let processedContent = content;
647
+ let blockCounter = 0;
648
+ // Process XML-like tags in order of priority
649
+ const tagProcessors = [
650
+ // Callouts: <callout type="info">content</callout>
651
+ {
652
+ regex: /<callout\s*(?:type="([^"]*)")?\s*>(.*?)<\/callout>/gis,
653
+ processor: (match, type = 'info', content) => {
654
+ const emoji = NotionAITool.getCalloutEmoji(type.toLowerCase());
655
+ const color = NotionAITool.getCalloutColor(type.toLowerCase());
656
+ blocks.push({
657
+ type: 'callout',
658
+ callout: {
659
+ rich_text: NotionAITool.parseBasicMarkdown(content.trim()),
660
+ icon: { type: 'emoji', emoji },
661
+ color: color,
662
+ },
663
+ });
664
+ return `__XML_BLOCK_${blockCounter++}__`;
665
+ }
666
+ },
667
+ // Code blocks: <code language="javascript">content</code>
668
+ {
669
+ regex: /<code\s*(?:language="([^"]*)")?\s*>(.*?)<\/code>/gis,
670
+ processor: (match, language = 'plain_text', content) => {
671
+ blocks.push({
672
+ type: 'code',
673
+ code: {
674
+ rich_text: [(0, NotionUtils_1.createRichText)(content.trim())],
675
+ language: language === 'plain text' ? 'plain_text' : language,
676
+ },
677
+ });
678
+ return `__XML_BLOCK_${blockCounter++}__`;
679
+ }
680
+ },
681
+ // Images: <image src="url" alt="description">caption</image>
682
+ {
683
+ regex: /<image\s+src="([^"]*)"(?:\s+alt="([^"]*)")?\s*>(.*?)<\/image>/gis,
684
+ processor: (match, src, alt = '', caption = '') => {
685
+ const captionText = caption.trim() || alt;
686
+ blocks.push({
687
+ type: 'image',
688
+ image: {
689
+ type: 'external',
690
+ external: { url: src },
691
+ caption: captionText ? NotionAITool.parseBasicMarkdown(captionText) : [],
692
+ },
693
+ });
694
+ return `__XML_BLOCK_${blockCounter++}__`;
695
+ }
696
+ },
697
+ // Self-closing images: <image src="url" alt="description"/>
698
+ {
699
+ regex: /<image\s+src="([^"]*)"(?:\s+alt="([^"]*)")?\s*\/>/gis,
700
+ processor: (match, src, alt = '') => {
701
+ blocks.push({
702
+ type: 'image',
703
+ image: {
704
+ type: 'external',
705
+ external: { url: src },
706
+ caption: alt ? NotionAITool.parseBasicMarkdown(alt) : [],
707
+ },
708
+ });
709
+ return `__XML_BLOCK_${blockCounter++}__`;
710
+ }
711
+ },
712
+ // Equations: <equation>E=mc^2</equation>
713
+ {
714
+ regex: /<equation>(.*?)<\/equation>/gis,
715
+ processor: (match, expression) => {
716
+ blocks.push({
717
+ type: 'equation',
718
+ equation: {
719
+ expression: expression.trim(),
720
+ },
721
+ });
722
+ return `__XML_BLOCK_${blockCounter++}__`;
723
+ }
724
+ },
725
+ // Embeds: <embed>url</embed>
726
+ {
727
+ regex: /<embed>(.*?)<\/embed>/gis,
728
+ processor: (match, url) => {
729
+ blocks.push({
730
+ type: 'embed',
731
+ embed: {
732
+ url: url.trim(),
733
+ },
734
+ });
735
+ return `__XML_BLOCK_${blockCounter++}__`;
736
+ }
737
+ },
738
+ // Bookmarks: <bookmark>url</bookmark>
739
+ {
740
+ regex: /<bookmark>(.*?)<\/bookmark>/gis,
741
+ processor: (match, url) => {
742
+ blocks.push({
743
+ type: 'bookmark',
744
+ bookmark: {
745
+ url: url.trim(),
746
+ },
747
+ });
748
+ return `__XML_BLOCK_${blockCounter++}__`;
749
+ }
750
+ },
751
+ // Toggles: <toggle>title</toggle>
752
+ {
753
+ regex: /<toggle>(.*?)<\/toggle>/gis,
754
+ processor: (match, title) => {
755
+ blocks.push({
756
+ type: 'toggle',
757
+ toggle: {
758
+ rich_text: NotionAITool.parseBasicMarkdown(title.trim()),
759
+ children: [],
760
+ },
761
+ });
762
+ return `__XML_BLOCK_${blockCounter++}__`;
763
+ }
764
+ },
765
+ // Quotes: <quote>content</quote>
766
+ {
767
+ regex: /<quote>(.*?)<\/quote>/gis,
768
+ processor: (match, content) => {
769
+ blocks.push({
770
+ type: 'quote',
771
+ quote: {
772
+ rich_text: NotionAITool.parseBasicMarkdown(content.trim()),
773
+ },
774
+ });
775
+ return `__XML_BLOCK_${blockCounter++}__`;
776
+ }
777
+ },
778
+ // Dividers: <divider/> or <divider></divider>
779
+ {
780
+ regex: /<divider\s*\/?>/gis,
781
+ processor: (match) => {
782
+ blocks.push({
783
+ type: 'divider',
784
+ divider: {},
785
+ });
786
+ return `__XML_BLOCK_${blockCounter++}__`;
787
+ }
788
+ },
789
+ // To-do items: <todo checked="true">content</todo>
790
+ {
791
+ regex: /<todo\s*(?:checked="([^"]*)")?\s*>(.*?)<\/todo>/gis,
792
+ processor: (match, checked = 'false', content) => {
793
+ const isChecked = checked.toLowerCase() === 'true';
794
+ blocks.push({
795
+ type: 'to_do',
796
+ to_do: {
797
+ rich_text: NotionAITool.parseBasicMarkdown(content.trim()),
798
+ checked: isChecked,
799
+ },
800
+ });
801
+ return `__XML_BLOCK_${blockCounter++}__`;
802
+ }
803
+ },
804
+ // Headings: <h1>content</h1>, <h2>content</h2>, <h3>content</h3>
805
+ {
806
+ regex: /<h([123])>(.*?)<\/h[123]>/gis,
807
+ processor: (match, level, content) => {
808
+ const headingType = `heading_${level}`;
809
+ blocks.push({
810
+ type: headingType,
811
+ [headingType]: {
812
+ rich_text: [(0, NotionUtils_1.createRichText)(content.trim())],
813
+ },
814
+ });
815
+ return `__XML_BLOCK_${blockCounter++}__`;
816
+ }
817
+ },
818
+ ];
819
+ // Process each tag type
820
+ tagProcessors.forEach(({ regex, processor }) => {
821
+ processedContent = processedContent.replace(regex, (match, group1, group2, group3) => {
822
+ return processor(match, group1 || '', group2 || '', group3 || '');
823
+ });
824
+ });
825
+ return processedContent;
826
+ }
827
+ // Helper function to get callout emoji based on type
828
+ static getCalloutEmoji(type) {
829
+ const emojiMap = {
830
+ 'info': 'ℹ️',
831
+ 'warning': '⚠️',
832
+ 'danger': '🚨',
833
+ 'error': '❌',
834
+ 'note': '📝',
835
+ 'tip': '💡',
836
+ 'success': '✅',
837
+ 'question': '❓',
838
+ };
839
+ return emojiMap[type] || 'ℹ️';
840
+ }
841
+ // Helper function to get callout color based on type
842
+ static getCalloutColor(type) {
843
+ const colorMap = {
844
+ 'info': 'blue',
845
+ 'warning': 'yellow',
846
+ 'danger': 'red',
847
+ 'error': 'red',
848
+ 'note': 'gray',
849
+ 'tip': 'green',
850
+ 'success': 'green',
851
+ 'question': 'purple',
852
+ };
853
+ return colorMap[type] || 'gray';
854
+ }
855
+ // Helper function to parse basic markdown formatting in text
856
+ static parseBasicMarkdown(text) {
857
+ const richTextObjects = [];
858
+ // Find and collect all formatting patterns with their positions
859
+ const patterns = [
860
+ { regex: /\[([^\]]+)\]\(([^)]+)\)/g, type: 'link' }, // [text](url)
861
+ { regex: /\*\*\*([^*]+)\*\*\*/g, type: 'bold_italic' }, // ***bold italic***
862
+ { regex: /\*\*([^*]+)\*\*/g, type: 'bold' }, // **bold**
863
+ { regex: /\*([^*]+)\*/g, type: 'italic' }, // *italic*
864
+ { regex: /~~([^~]+)~~/g, type: 'strikethrough' }, // ~~strikethrough~~
865
+ { regex: /`([^`]+)`/g, type: 'code' }, // `code`
866
+ ];
867
+ const matches = [];
868
+ // Collect all matches
869
+ patterns.forEach(pattern => {
870
+ const regex = new RegExp(pattern.regex.source, 'g');
871
+ let match;
872
+ while ((match = regex.exec(text)) !== null) {
873
+ if (pattern.type === 'link') {
874
+ matches.push({
875
+ start: match.index,
876
+ end: match.index + match[0].length,
877
+ text: match[1], // Link text
878
+ type: pattern.type,
879
+ url: match[2] // Link URL
880
+ });
881
+ }
882
+ else {
883
+ matches.push({
884
+ start: match.index,
885
+ end: match.index + match[0].length,
886
+ text: match[1], // Inner text
887
+ type: pattern.type
888
+ });
889
+ }
890
+ }
891
+ });
892
+ // Sort matches by position and resolve overlaps (prefer longer matches)
893
+ matches.sort((a, b) => {
894
+ if (a.start !== b.start)
895
+ return a.start - b.start;
896
+ return (b.end - b.start) - (a.end - a.start); // Prefer longer matches
897
+ });
898
+ // Remove overlapping matches (keep the first/longer one)
899
+ const resolvedMatches = [];
900
+ for (const match of matches) {
901
+ const hasOverlap = resolvedMatches.some(existing => (match.start < existing.end && match.end > existing.start));
902
+ if (!hasOverlap) {
903
+ resolvedMatches.push(match);
904
+ }
905
+ }
906
+ // Sort again by position
907
+ resolvedMatches.sort((a, b) => a.start - b.start);
908
+ // If no formatting found, return simple rich text
909
+ if (resolvedMatches.length === 0) {
910
+ return [(0, NotionUtils_1.createRichText)(text)];
911
+ }
912
+ // Build rich text segments
913
+ let lastIndex = 0;
914
+ resolvedMatches.forEach(match => {
915
+ // Add plain text before this match
916
+ if (match.start > lastIndex) {
917
+ const plainText = text.substring(lastIndex, match.start);
918
+ if (plainText) {
919
+ richTextObjects.push((0, NotionUtils_1.createRichText)(plainText));
920
+ }
921
+ }
922
+ // Add formatted text
923
+ const richTextObj = {
924
+ type: 'text',
925
+ text: { content: match.text },
926
+ annotations: {}
927
+ };
928
+ // Apply formatting based on type
929
+ switch (match.type) {
930
+ case 'bold':
931
+ richTextObj.annotations.bold = true;
932
+ break;
933
+ case 'italic':
934
+ richTextObj.annotations.italic = true;
935
+ break;
936
+ case 'bold_italic':
937
+ richTextObj.annotations.bold = true;
938
+ richTextObj.annotations.italic = true;
939
+ break;
940
+ case 'strikethrough':
941
+ richTextObj.annotations.strikethrough = true;
942
+ break;
943
+ case 'code':
944
+ richTextObj.annotations.code = true;
945
+ break;
946
+ case 'link':
947
+ richTextObj.text.link = { url: match.url };
948
+ break;
949
+ }
950
+ // Clean up empty annotations
951
+ if (Object.keys(richTextObj.annotations).length === 0) {
952
+ delete richTextObj.annotations;
953
+ }
954
+ richTextObjects.push(richTextObj);
955
+ lastIndex = match.end;
956
+ });
957
+ // Add remaining plain text
958
+ if (lastIndex < text.length) {
959
+ const remainingText = text.substring(lastIndex);
960
+ if (remainingText) {
961
+ richTextObjects.push((0, NotionUtils_1.createRichText)(remainingText));
962
+ }
963
+ }
964
+ return richTextObjects.length > 0 ? richTextObjects : [(0, NotionUtils_1.createRichText)(text)];
965
+ }
539
966
  static parsePropertiesToUpdate(propertiesString) {
540
967
  try {
541
968
  // Try to parse as JSON first
@@ -64,6 +64,10 @@ export declare function createBookmarkBlock(url: string, caption?: RichTextObjec
64
64
  * Creates an embed block
65
65
  */
66
66
  export declare function createEmbedBlock(url: string, caption?: RichTextObject[]): Block;
67
+ /**
68
+ * Creates a toggle block
69
+ */
70
+ export declare function createToggleBlock(text: string | RichTextObject[], color?: NotionColor, children?: Block[]): Block;
67
71
  /**
68
72
  * Creates a table block with rows
69
73
  */
@@ -16,6 +16,7 @@ exports.createEquationBlock = createEquationBlock;
16
16
  exports.createImageBlock = createImageBlock;
17
17
  exports.createBookmarkBlock = createBookmarkBlock;
18
18
  exports.createEmbedBlock = createEmbedBlock;
19
+ exports.createToggleBlock = createToggleBlock;
19
20
  exports.createTableBlock = createTableBlock;
20
21
  exports.convertBlockInput = convertBlockInput;
21
22
  exports.resolvePageId = resolvePageId;
@@ -294,6 +295,19 @@ function createEmbedBlock(url, caption) {
294
295
  },
295
296
  };
296
297
  }
298
+ /**
299
+ * Creates a toggle block
300
+ */
301
+ function createToggleBlock(text, color, children) {
302
+ return {
303
+ type: 'toggle',
304
+ toggle: {
305
+ rich_text: typeof text === 'string' ? [createRichText(text)] : text,
306
+ color,
307
+ children,
308
+ },
309
+ };
310
+ }
297
311
  /**
298
312
  * Creates a table block with rows
299
313
  */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "n8n-nodes-notion-advanced",
3
- "version": "1.1.31-beta",
3
+ "version": "1.2.0-beta",
4
4
  "description": "Advanced n8n Notion nodes: Full-featured workflow node + AI Agent Tool for intelligent Notion automation with 25+ block types (BETA)",
5
5
  "scripts": {
6
6
  "build": "echo 'Already built'",