n8n-nodes-notion-advanced 1.1.18-beta → 1.1.19-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.
@@ -1,634 +1,565 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.NotionAITool = void 0;
4
- const n8n_workflow_1 = require("n8n-workflow");
5
- const NotionUtils_1 = require("./NotionUtils");
6
-
7
- class NotionAITool {
8
- constructor() {
9
- this.description = {
10
- displayName: 'Notion AI Tool',
11
- name: 'notionAiTool',
12
- icon: 'file:notion.svg',
13
- group: ['ai'],
14
- version: 1,
15
- subtitle: '={{$parameter["operation"]}}',
16
- description: 'AI-powered tool for creating and managing Notion content. Designed for use with AI Agent Nodes.',
17
- defaults: {
18
- name: 'Notion AI Tool',
19
- },
20
- inputs: ['main'],
21
- outputs: ['main'],
22
- codex: {
23
- categories: ['Productivity', 'AI', 'Documentation'],
24
- subcategories: {
25
- 'Productivity': ['Notion', 'Knowledge Management'],
26
- 'AI': ['AI Agent Tools', 'Natural Language Processing'],
27
- 'Documentation': ['Page Creation', 'Content Management']
28
- },
29
- resources: {
30
- primaryDocumentation: [
31
- {
32
- url: 'https://github.com/AZ-IT-US/n8n-notion-advanced-node#ai-tool-usage',
33
- },
34
- ],
35
- },
36
- alias: ['notion', 'productivity', 'ai-tool', 'pages', 'database'],
37
- },
38
- credentials: [
39
- {
40
- name: 'notionApi',
41
- required: true,
42
- },
43
- ],
44
- properties: [
45
- {
46
- displayName: 'Operation',
47
- name: 'operation',
48
- type: 'options',
49
- noDataExpression: true,
50
- options: [
51
- {
52
- name: 'Create Page with Content',
53
- value: 'createPageWithContent',
54
- description: 'Create a new Notion page with structured content including text, headings, lists, and formatting',
55
- action: 'Create a Notion page with content',
56
- },
57
- {
58
- name: 'Add Content to Page',
59
- value: 'addContentToPage',
60
- description: 'Append new content blocks (paragraphs, headings, lists, etc.) to an existing Notion page',
61
- action: 'Add content to existing page',
62
- },
63
- {
64
- name: 'Search and Retrieve Pages',
65
- value: 'searchPages',
66
- description: 'Search for Notion pages by title, content, or properties and retrieve their information',
67
- action: 'Search and retrieve pages',
68
- },
69
- {
70
- name: 'Update Page Properties',
71
- value: 'updatePageProperties',
72
- description: 'Update page title, properties, status, tags, or other metadata',
73
- action: 'Update page properties',
74
- },
75
- {
76
- name: 'Create Database Entry',
77
- value: 'createDatabaseEntry',
78
- description: 'Create a new entry in a Notion database with specified properties and values',
79
- action: 'Create database entry',
80
- },
81
- {
82
- name: 'Query Database',
83
- value: 'queryDatabase',
84
- description: 'Search and filter database entries based on criteria and retrieve matching records',
85
- action: 'Query database',
86
- },
87
- ],
88
- default: 'createPageWithContent',
89
- },
90
- // CREATE PAGE WITH CONTENT
91
- {
92
- displayName: 'Page Title',
93
- name: 'pageTitle',
94
- type: 'string',
95
- required: true,
96
- displayOptions: {
97
- show: {
98
- operation: ['createPageWithContent'],
99
- },
100
- },
101
- default: '',
102
- description: 'The title of the new page to create',
103
- },
104
- {
105
- displayName: 'Parent Page/Database ID',
106
- name: 'parentId',
107
- type: 'string',
108
- required: true,
109
- displayOptions: {
110
- show: {
111
- operation: ['createPageWithContent', 'createDatabaseEntry'],
112
- },
113
- },
114
- default: '',
115
- description: 'ID of the parent page or database where this should be created. Can be a Notion URL or page ID.',
116
- },
117
- {
118
- displayName: 'Content',
119
- name: 'content',
120
- type: 'string',
121
- typeOptions: {
122
- rows: 6,
123
- },
124
- displayOptions: {
125
- show: {
126
- operation: ['createPageWithContent', 'addContentToPage'],
127
- },
128
- },
129
- default: '',
130
- description: 'The content to add. Use natural language - AI will structure it into appropriate blocks (headings, paragraphs, lists, etc.)',
131
- placeholder: 'Example:\n# Main Heading\nThis is a paragraph with **bold** and *italic* text.\n\n## Subheading\n- First bullet point\n- Second bullet point\n\n> This is a quote block',
132
- },
133
- // ADD CONTENT TO PAGE
134
- {
135
- displayName: 'Target Page ID',
136
- name: 'targetPageId',
137
- type: 'string',
138
- required: true,
139
- displayOptions: {
140
- show: {
141
- operation: ['addContentToPage', 'updatePageProperties'],
142
- },
143
- },
144
- default: '',
145
- description: 'ID or URL of the existing page to modify',
146
- },
147
- // SEARCH PAGES
148
- {
149
- displayName: 'Search Query',
150
- name: 'searchQuery',
151
- type: 'string',
152
- displayOptions: {
153
- show: {
154
- operation: ['searchPages'],
155
- },
156
- },
157
- default: '',
158
- description: 'Search terms to find pages. Leave empty to get all pages.',
159
- },
160
- {
161
- displayName: 'Search Type',
162
- name: 'searchType',
163
- type: 'options',
164
- displayOptions: {
165
- show: {
166
- operation: ['searchPages'],
167
- },
168
- },
169
- options: [
170
- {
171
- name: 'All Content',
172
- value: 'all',
173
- description: 'Search in page titles and content',
174
- },
175
- {
176
- name: 'Titles Only',
177
- value: 'title',
178
- description: 'Search only in page titles',
179
- },
180
- {
181
- name: 'Recent Pages',
182
- value: 'recent',
183
- description: 'Get recently modified pages',
184
- },
185
- ],
186
- default: 'all',
187
- },
188
- // UPDATE PAGE PROPERTIES
189
- {
190
- displayName: 'Properties to Update',
191
- name: 'propertiesToUpdate',
192
- type: 'string',
193
- typeOptions: {
194
- rows: 4,
195
- },
196
- displayOptions: {
197
- show: {
198
- operation: ['updatePageProperties'],
199
- },
200
- },
201
- default: '',
202
- description: 'Properties to update in JSON format or natural language. Example: {"status": "In Progress", "priority": "High"} or "Set status to Done and priority to Low"',
203
- },
204
- // DATABASE OPERATIONS
205
- {
206
- displayName: 'Database ID',
207
- name: 'databaseId',
208
- type: 'string',
209
- required: true,
210
- displayOptions: {
211
- show: {
212
- operation: ['queryDatabase'],
213
- },
214
- },
215
- default: '',
216
- description: 'ID or URL of the database to query',
217
- },
218
- {
219
- displayName: 'Entry Properties',
220
- name: 'entryProperties',
221
- type: 'string',
222
- typeOptions: {
223
- rows: 4,
224
- },
225
- displayOptions: {
226
- show: {
227
- operation: ['createDatabaseEntry'],
228
- },
229
- },
230
- default: '',
231
- description: 'Properties for the new database entry in JSON format or natural language description',
232
- },
233
- {
234
- displayName: 'Query Filter',
235
- name: 'queryFilter',
236
- type: 'string',
237
- displayOptions: {
238
- show: {
239
- operation: ['queryDatabase'],
240
- },
241
- },
242
- default: '',
243
- description: 'Filter criteria in natural language (e.g., "status is Done and priority is High") or JSON format',
244
- },
245
- // COMMON OPTIONS
246
- {
247
- displayName: 'Additional Options',
248
- name: 'additionalOptions',
249
- type: 'collection',
250
- placeholder: 'Add Option',
251
- default: {},
252
- options: [
253
- {
254
- displayName: 'Icon',
255
- name: 'icon',
256
- type: 'string',
257
- default: '',
258
- description: 'Emoji icon for the page (e.g., 📝, 🎯, 📊)',
259
- },
260
- {
261
- displayName: 'Cover Image URL',
262
- name: 'coverUrl',
263
- type: 'string',
264
- default: '',
265
- description: 'URL of cover image for the page',
266
- },
267
- {
268
- displayName: 'Return Full Content',
269
- name: 'returnFullContent',
270
- type: 'boolean',
271
- default: false,
272
- description: 'Whether to return full page content or just metadata',
273
- },
274
- {
275
- displayName: 'Max Results',
276
- name: 'maxResults',
277
- type: 'number',
278
- default: 20,
279
- description: 'Maximum number of results to return (1-100)',
280
- },
281
- ],
282
- },
283
- ],
284
- };
285
- }
286
-
287
- async execute() {
288
- const items = this.getInputData();
289
- const responseData = [];
290
-
291
- // Validate credentials
292
- const isValid = await NotionUtils_1.validateCredentials.call(this);
293
- if (!isValid) {
294
- throw new n8n_workflow_1.NodeOperationError(this.getNode(), 'Invalid Notion API credentials');
295
- }
296
-
297
- for (let i = 0; i < items.length; i++) {
298
- try {
299
- const operation = this.getNodeParameter('operation', i);
300
- let result;
301
-
302
- switch (operation) {
303
- case 'createPageWithContent':
304
- result = await this.createPageWithContent(i);
305
- break;
306
- case 'addContentToPage':
307
- result = await this.addContentToPage(i);
308
- break;
309
- case 'searchPages':
310
- result = await this.searchPages(i);
311
- break;
312
- case 'updatePageProperties':
313
- result = await this.updatePageProperties(i);
314
- break;
315
- case 'createDatabaseEntry':
316
- result = await this.createDatabaseEntry(i);
317
- break;
318
- case 'queryDatabase':
319
- result = await this.queryDatabase(i);
320
- break;
321
- default:
322
- throw new n8n_workflow_1.NodeOperationError(this.getNode(), `Unknown operation: ${operation}`);
323
- }
324
-
325
- responseData.push({
326
- operation,
327
- success: true,
328
- ...result,
329
- });
330
- } catch (error) {
331
- if (this.continueOnFail()) {
332
- responseData.push({
333
- error: error.message,
334
- success: false,
335
- });
336
- } else {
337
- throw error;
338
- }
339
- }
340
- }
341
-
342
- return [this.helpers.returnJsonArray(responseData)];
343
- }
344
-
345
- async createPageWithContent(itemIndex) {
346
- const pageTitle = this.getNodeParameter('pageTitle', itemIndex);
347
- const parentId = this.getNodeParameter('parentId', itemIndex);
348
- const content = this.getNodeParameter('content', itemIndex, '');
349
- const additionalOptions = this.getNodeParameter('additionalOptions', itemIndex, {});
350
-
351
- const resolvedParentId = await NotionUtils_1.resolvePageId.call(this, parentId);
352
-
353
- // Create the page first
354
- const pageBody = {
355
- parent: { page_id: resolvedParentId },
356
- properties: {
357
- title: {
358
- title: [NotionUtils_1.createRichText(pageTitle)],
359
- },
360
- },
361
- };
362
-
363
- // Add icon and cover if provided
364
- if (additionalOptions.icon) {
365
- pageBody.icon = { type: 'emoji', emoji: additionalOptions.icon };
366
- }
367
- if (additionalOptions.coverUrl) {
368
- pageBody.cover = { type: 'external', external: { url: additionalOptions.coverUrl } };
369
- }
370
-
371
- const page = await NotionUtils_1.notionApiRequest.call(this, 'POST', '/pages', pageBody);
372
-
373
- // If content is provided, add it to the page
374
- if (content) {
375
- const blocks = this.parseContentToBlocks(content);
376
- if (blocks.length > 0) {
377
- await NotionUtils_1.notionApiRequest.call(this, 'PATCH', `/blocks/${page.id}/children`, {
378
- children: blocks,
379
- });
380
- }
381
- }
382
-
383
- return {
384
- pageId: page.id,
385
- title: pageTitle,
386
- url: page.url,
387
- message: `Created page "${pageTitle}" with content`,
388
- };
389
- }
390
-
391
- async addContentToPage(itemIndex) {
392
- const targetPageId = this.getNodeParameter('targetPageId', itemIndex);
393
- const content = this.getNodeParameter('content', itemIndex);
394
-
395
- const resolvedPageId = await NotionUtils_1.resolvePageId.call(this, targetPageId);
396
- const blocks = this.parseContentToBlocks(content);
397
-
398
- if (blocks.length === 0) {
399
- throw new n8n_workflow_1.NodeOperationError(this.getNode(), 'No valid content blocks found to add');
400
- }
401
-
402
- const result = await NotionUtils_1.notionApiRequest.call(this, 'PATCH', `/blocks/${resolvedPageId}/children`, {
403
- children: blocks,
404
- });
405
-
406
- return {
407
- pageId: resolvedPageId,
408
- blocksAdded: blocks.length,
409
- message: `Added ${blocks.length} content blocks to page`,
410
- result,
411
- };
412
- }
413
-
414
- async searchPages(itemIndex) {
415
- const searchQuery = this.getNodeParameter('searchQuery', itemIndex, '');
416
- const searchType = this.getNodeParameter('searchType', itemIndex, 'all');
417
- const additionalOptions = this.getNodeParameter('additionalOptions', itemIndex, {});
418
- const maxResults = additionalOptions.maxResults || 20;
419
-
420
- const body = {
421
- page_size: Math.min(maxResults, 100),
422
- };
423
-
424
- if (searchQuery) {
425
- body.query = searchQuery;
426
- }
427
-
428
- body.filter = {
429
- property: 'object',
430
- value: 'page',
431
- };
432
-
433
- const response = await NotionUtils_1.notionApiRequest.call(this, 'POST', '/search', body);
434
-
435
- return {
436
- totalResults: response.results?.length || 0,
437
- pages: response.results || [],
438
- message: `Found ${response.results?.length || 0} pages`,
439
- };
440
- }
441
-
442
- async updatePageProperties(itemIndex) {
443
- const targetPageId = this.getNodeParameter('targetPageId', itemIndex);
444
- const propertiesToUpdate = this.getNodeParameter('propertiesToUpdate', itemIndex);
445
-
446
- const resolvedPageId = await NotionUtils_1.resolvePageId.call(this, targetPageId);
447
- const properties = this.parsePropertiesToUpdate(propertiesToUpdate);
448
-
449
- const result = await NotionUtils_1.notionApiRequest.call(this, 'PATCH', `/pages/${resolvedPageId}`, {
450
- properties,
451
- });
452
-
453
- return {
454
- pageId: resolvedPageId,
455
- updatedProperties: Object.keys(properties),
456
- message: `Updated ${Object.keys(properties).length} properties`,
457
- result,
458
- };
459
- }
460
-
461
- async createDatabaseEntry(itemIndex) {
462
- const parentId = this.getNodeParameter('parentId', itemIndex);
463
- const entryProperties = this.getNodeParameter('entryProperties', itemIndex);
464
-
465
- const resolvedParentId = await NotionUtils_1.resolvePageId.call(this, parentId);
466
- const properties = this.parsePropertiesToUpdate(entryProperties);
467
-
468
- const result = await NotionUtils_1.notionApiRequest.call(this, 'POST', '/pages', {
469
- parent: { database_id: resolvedParentId },
470
- properties,
471
- });
472
-
473
- return {
474
- entryId: result.id,
475
- databaseId: resolvedParentId,
476
- message: 'Created new database entry',
477
- result,
478
- };
479
- }
480
-
481
- async queryDatabase(itemIndex) {
482
- const databaseId = this.getNodeParameter('databaseId', itemIndex);
483
- const queryFilter = this.getNodeParameter('queryFilter', itemIndex, '');
484
- const additionalOptions = this.getNodeParameter('additionalOptions', itemIndex, {});
485
- const maxResults = additionalOptions.maxResults || 20;
486
-
487
- const resolvedDatabaseId = await NotionUtils_1.resolvePageId.call(this, databaseId);
488
- const body = {
489
- page_size: Math.min(maxResults, 100),
490
- };
491
-
492
- if (queryFilter) {
493
- try {
494
- body.filter = JSON.parse(queryFilter);
495
- } catch {
496
- // If not JSON, create a simple text filter
497
- body.filter = {
498
- property: 'Name',
499
- title: {
500
- contains: queryFilter,
501
- },
502
- };
503
- }
504
- }
505
-
506
- const response = await NotionUtils_1.notionApiRequest.call(this, 'POST', `/databases/${resolvedDatabaseId}/query`, body);
507
-
508
- return {
509
- databaseId: resolvedDatabaseId,
510
- totalResults: response.results?.length || 0,
511
- entries: response.results || [],
512
- message: `Found ${response.results?.length || 0} database entries`,
513
- };
514
- }
515
-
516
- parseContentToBlocks(content) {
517
- const blocks = [];
518
- const lines = content.split('\n');
519
-
520
- for (let i = 0; i < lines.length; i++) {
521
- const line = lines[i].trim();
522
- if (!line) continue;
523
-
524
- // Parse different content types
525
- if (line.startsWith('# ')) {
526
- blocks.push({
527
- object: 'block',
528
- type: 'heading_1',
529
- heading_1: {
530
- rich_text: [NotionUtils_1.createRichText(line.substring(2))],
531
- },
532
- });
533
- } else if (line.startsWith('## ')) {
534
- blocks.push({
535
- object: 'block',
536
- type: 'heading_2',
537
- heading_2: {
538
- rich_text: [NotionUtils_1.createRichText(line.substring(3))],
539
- },
540
- });
541
- } else if (line.startsWith('### ')) {
542
- blocks.push({
543
- object: 'block',
544
- type: 'heading_3',
545
- heading_3: {
546
- rich_text: [NotionUtils_1.createRichText(line.substring(4))],
547
- },
548
- });
549
- } else if (line.startsWith('- ') || line.startsWith('* ')) {
550
- blocks.push({
551
- object: 'block',
552
- type: 'bulleted_list_item',
553
- bulleted_list_item: {
554
- rich_text: [NotionUtils_1.createRichText(line.substring(2))],
555
- },
556
- });
557
- } else if (line.match(/^\d+\. /)) {
558
- blocks.push({
559
- object: 'block',
560
- type: 'numbered_list_item',
561
- numbered_list_item: {
562
- rich_text: [NotionUtils_1.createRichText(line.replace(/^\d+\. /, ''))],
563
- },
564
- });
565
- } else if (line.startsWith('> ')) {
566
- blocks.push({
567
- object: 'block',
568
- type: 'quote',
569
- quote: {
570
- rich_text: [NotionUtils_1.createRichText(line.substring(2))],
571
- },
572
- });
573
- } else if (line.startsWith('```')) {
574
- // Handle code blocks
575
- const codeLines = [];
576
- i++; // Skip the opening ```
577
- while (i < lines.length && !lines[i].trim().startsWith('```')) {
578
- codeLines.push(lines[i]);
579
- i++;
580
- }
581
- blocks.push({
582
- object: 'block',
583
- type: 'code',
584
- code: {
585
- rich_text: [NotionUtils_1.createRichText(codeLines.join('\n'))],
586
- language: 'plain text',
587
- },
588
- });
589
- } else {
590
- // Regular paragraph
591
- blocks.push({
592
- object: 'block',
593
- type: 'paragraph',
594
- paragraph: {
595
- rich_text: [NotionUtils_1.createRichText(line)],
596
- },
597
- });
598
- }
599
- }
600
-
601
- return blocks;
602
- }
603
-
604
- parsePropertiesToUpdate(propertiesString) {
605
- try {
606
- // Try to parse as JSON first
607
- return JSON.parse(propertiesString);
608
- } catch {
609
- // If not JSON, try to parse natural language
610
- const properties = {};
611
-
612
- // Simple natural language parsing
613
- const patterns = [
614
- /set\s+(\w+)\s+to\s+(.+?)(?:\s+and|$)/gi,
615
- /(\w+)\s*:\s*(.+?)(?:\s*,|$)/gi,
616
- /(\w+)\s*=\s*(.+?)(?:\s*,|$)/gi,
617
- ];
618
-
619
- for (const pattern of patterns) {
620
- let match;
621
- while ((match = pattern.exec(propertiesString)) !== null) {
622
- const [, key, value] = match;
623
- properties[key.trim()] = {
624
- rich_text: [NotionUtils_1.createRichText(value.trim())],
625
- };
626
- }
627
- }
628
-
629
- return properties;
630
- }
631
- }
632
- }
633
-
634
- exports.NotionAITool = NotionAITool;
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.NotionAITool = void 0;
4
+ const n8n_workflow_1 = require("n8n-workflow");
5
+ const NotionUtils_1 = require("./NotionUtils");
6
+ class NotionAITool {
7
+ constructor() {
8
+ this.description = {
9
+ displayName: 'Notion AI Tool',
10
+ name: 'notionAiTool',
11
+ icon: 'file:notion.svg',
12
+ group: ['ai'],
13
+ version: 1,
14
+ subtitle: '={{$parameter["operation"]}}',
15
+ description: 'AI-powered tool for creating and managing Notion content. Designed for use with AI Agent Nodes.',
16
+ defaults: {
17
+ name: 'Notion AI Tool',
18
+ },
19
+ inputs: ["main" /* NodeConnectionType.Main */],
20
+ outputs: ["main" /* NodeConnectionType.Main */],
21
+ codex: {
22
+ categories: ['Productivity', 'AI', 'Documentation'],
23
+ subcategories: {
24
+ 'Productivity': ['Notion', 'Knowledge Management'],
25
+ 'AI': ['AI Agent Tools', 'Natural Language Processing'],
26
+ 'Documentation': ['Page Creation', 'Content Management']
27
+ },
28
+ resources: {
29
+ primaryDocumentation: [
30
+ {
31
+ url: 'https://github.com/AZ-IT-US/n8n-notion-advanced-node#ai-tool-usage',
32
+ },
33
+ ],
34
+ },
35
+ alias: ['notion', 'productivity', 'ai-tool', 'pages', 'database'],
36
+ },
37
+ credentials: [
38
+ {
39
+ name: 'notionApi',
40
+ required: true,
41
+ },
42
+ ],
43
+ properties: [
44
+ {
45
+ displayName: 'Operation',
46
+ name: 'operation',
47
+ type: 'options',
48
+ noDataExpression: true,
49
+ options: [
50
+ {
51
+ name: 'Create Page with Content',
52
+ value: 'createPageWithContent',
53
+ description: 'Create a new Notion page with structured content including text, headings, lists, and formatting',
54
+ action: 'Create a Notion page with content',
55
+ },
56
+ {
57
+ name: 'Add Content to Page',
58
+ value: 'addContentToPage',
59
+ description: 'Append new content blocks (paragraphs, headings, lists, etc.) to an existing Notion page',
60
+ action: 'Add content to existing page',
61
+ },
62
+ {
63
+ name: 'Search and Retrieve Pages',
64
+ value: 'searchPages',
65
+ description: 'Search for Notion pages by title, content, or properties and retrieve their information',
66
+ action: 'Search and retrieve pages',
67
+ },
68
+ {
69
+ name: 'Update Page Properties',
70
+ value: 'updatePageProperties',
71
+ description: 'Update page title, properties, status, tags, or other metadata',
72
+ action: 'Update page properties',
73
+ },
74
+ {
75
+ name: 'Create Database Entry',
76
+ value: 'createDatabaseEntry',
77
+ description: 'Create a new entry in a Notion database with specified properties and values',
78
+ action: 'Create database entry',
79
+ },
80
+ {
81
+ name: 'Query Database',
82
+ value: 'queryDatabase',
83
+ description: 'Search and filter database entries based on criteria and retrieve matching records',
84
+ action: 'Query database',
85
+ },
86
+ ],
87
+ default: 'createPageWithContent',
88
+ },
89
+ // CREATE PAGE WITH CONTENT
90
+ {
91
+ displayName: 'Page Title',
92
+ name: 'pageTitle',
93
+ type: 'string',
94
+ required: true,
95
+ displayOptions: {
96
+ show: {
97
+ operation: ['createPageWithContent'],
98
+ },
99
+ },
100
+ default: '',
101
+ description: 'The title of the new page to create',
102
+ },
103
+ {
104
+ displayName: 'Parent Page/Database ID',
105
+ name: 'parentId',
106
+ type: 'string',
107
+ required: true,
108
+ displayOptions: {
109
+ show: {
110
+ operation: ['createPageWithContent', 'createDatabaseEntry'],
111
+ },
112
+ },
113
+ default: '',
114
+ description: 'ID of the parent page or database where this should be created. Can be a Notion URL or page ID.',
115
+ },
116
+ {
117
+ displayName: 'Content',
118
+ name: 'content',
119
+ type: 'string',
120
+ typeOptions: {
121
+ rows: 6,
122
+ },
123
+ displayOptions: {
124
+ show: {
125
+ operation: ['createPageWithContent', 'addContentToPage'],
126
+ },
127
+ },
128
+ default: '',
129
+ description: 'The content to add. Use natural language - AI will structure it into appropriate blocks (headings, paragraphs, lists, etc.)',
130
+ placeholder: 'Example:\n# Main Heading\nThis is a paragraph with **bold** and *italic* text.\n\n## Subheading\n- First bullet point\n- Second bullet point\n\n> This is a quote block',
131
+ },
132
+ // ADD CONTENT TO PAGE
133
+ {
134
+ displayName: 'Target Page ID',
135
+ name: 'targetPageId',
136
+ type: 'string',
137
+ required: true,
138
+ displayOptions: {
139
+ show: {
140
+ operation: ['addContentToPage', 'updatePageProperties'],
141
+ },
142
+ },
143
+ default: '',
144
+ description: 'ID or URL of the existing page to modify',
145
+ },
146
+ // SEARCH PAGES
147
+ {
148
+ displayName: 'Search Query',
149
+ name: 'searchQuery',
150
+ type: 'string',
151
+ displayOptions: {
152
+ show: {
153
+ operation: ['searchPages'],
154
+ },
155
+ },
156
+ default: '',
157
+ description: 'Search terms to find pages. Leave empty to get all pages.',
158
+ },
159
+ // UPDATE PAGE PROPERTIES
160
+ {
161
+ displayName: 'Properties to Update',
162
+ name: 'propertiesToUpdate',
163
+ type: 'string',
164
+ typeOptions: {
165
+ rows: 4,
166
+ },
167
+ displayOptions: {
168
+ show: {
169
+ operation: ['updatePageProperties'],
170
+ },
171
+ },
172
+ default: '',
173
+ description: 'Properties to update in JSON format or natural language. Example: {"status": "In Progress", "priority": "High"} or "Set status to Done and priority to Low"',
174
+ },
175
+ // DATABASE OPERATIONS
176
+ {
177
+ displayName: 'Database ID',
178
+ name: 'databaseId',
179
+ type: 'string',
180
+ required: true,
181
+ displayOptions: {
182
+ show: {
183
+ operation: ['queryDatabase'],
184
+ },
185
+ },
186
+ default: '',
187
+ description: 'ID or URL of the database to query',
188
+ },
189
+ {
190
+ displayName: 'Entry Properties',
191
+ name: 'entryProperties',
192
+ type: 'string',
193
+ typeOptions: {
194
+ rows: 4,
195
+ },
196
+ displayOptions: {
197
+ show: {
198
+ operation: ['createDatabaseEntry'],
199
+ },
200
+ },
201
+ default: '',
202
+ description: 'Properties for the new database entry in JSON format or natural language description',
203
+ },
204
+ {
205
+ displayName: 'Query Filter',
206
+ name: 'queryFilter',
207
+ type: 'string',
208
+ displayOptions: {
209
+ show: {
210
+ operation: ['queryDatabase'],
211
+ },
212
+ },
213
+ default: '',
214
+ description: 'Filter criteria in natural language (e.g., "status is Done and priority is High") or JSON format',
215
+ },
216
+ // COMMON OPTIONS
217
+ {
218
+ displayName: 'Additional Options',
219
+ name: 'additionalOptions',
220
+ type: 'collection',
221
+ placeholder: 'Add Option',
222
+ default: {},
223
+ options: [
224
+ {
225
+ displayName: 'Icon',
226
+ name: 'icon',
227
+ type: 'string',
228
+ default: '',
229
+ description: 'Emoji icon for the page (e.g., 📝, 🎯, 📊)',
230
+ },
231
+ {
232
+ displayName: 'Cover Image URL',
233
+ name: 'coverUrl',
234
+ type: 'string',
235
+ default: '',
236
+ description: 'URL of cover image for the page',
237
+ },
238
+ {
239
+ displayName: 'Max Results',
240
+ name: 'maxResults',
241
+ type: 'number',
242
+ default: 20,
243
+ description: 'Maximum number of results to return (1-100)',
244
+ },
245
+ ],
246
+ },
247
+ ],
248
+ };
249
+ }
250
+ async execute() {
251
+ const items = this.getInputData();
252
+ const responseData = [];
253
+ // Validate credentials
254
+ const isValid = await NotionUtils_1.validateCredentials.call(this);
255
+ if (!isValid) {
256
+ throw new n8n_workflow_1.NodeOperationError(this.getNode(), 'Invalid Notion API credentials');
257
+ }
258
+ for (let i = 0; i < items.length; i++) {
259
+ try {
260
+ const operation = this.getNodeParameter('operation', i);
261
+ let result;
262
+ switch (operation) {
263
+ case 'createPageWithContent':
264
+ result = await NotionAITool.createPageWithContent(this, i);
265
+ break;
266
+ case 'addContentToPage':
267
+ result = await NotionAITool.addContentToPage(this, i);
268
+ break;
269
+ case 'searchPages':
270
+ result = await NotionAITool.searchPages(this, i);
271
+ break;
272
+ case 'updatePageProperties':
273
+ result = await NotionAITool.updatePageProperties(this, i);
274
+ break;
275
+ case 'createDatabaseEntry':
276
+ result = await NotionAITool.createDatabaseEntry(this, i);
277
+ break;
278
+ case 'queryDatabase':
279
+ result = await NotionAITool.queryDatabase(this, i);
280
+ break;
281
+ default:
282
+ throw new n8n_workflow_1.NodeOperationError(this.getNode(), `Unknown operation: ${operation}`);
283
+ }
284
+ responseData.push({
285
+ operation,
286
+ success: true,
287
+ ...result,
288
+ });
289
+ }
290
+ catch (error) {
291
+ if (this.continueOnFail()) {
292
+ responseData.push({
293
+ error: error.message,
294
+ success: false,
295
+ });
296
+ }
297
+ else {
298
+ throw error;
299
+ }
300
+ }
301
+ }
302
+ return [this.helpers.returnJsonArray(responseData)];
303
+ }
304
+ static async createPageWithContent(executeFunctions, itemIndex) {
305
+ const pageTitle = executeFunctions.getNodeParameter('pageTitle', itemIndex);
306
+ const parentId = executeFunctions.getNodeParameter('parentId', itemIndex);
307
+ const content = executeFunctions.getNodeParameter('content', itemIndex, '');
308
+ const additionalOptions = executeFunctions.getNodeParameter('additionalOptions', itemIndex, {});
309
+ const resolvedParentId = await NotionUtils_1.resolvePageId.call(executeFunctions, parentId);
310
+ // Create the page first
311
+ const pageBody = {
312
+ parent: { page_id: resolvedParentId },
313
+ properties: {
314
+ title: {
315
+ title: [(0, NotionUtils_1.createRichText)(pageTitle)],
316
+ },
317
+ },
318
+ };
319
+ // Add icon and cover if provided
320
+ if (additionalOptions.icon) {
321
+ pageBody.icon = { type: 'emoji', emoji: additionalOptions.icon };
322
+ }
323
+ if (additionalOptions.coverUrl) {
324
+ pageBody.cover = { type: 'external', external: { url: additionalOptions.coverUrl } };
325
+ }
326
+ const page = await NotionUtils_1.notionApiRequest.call(executeFunctions, 'POST', '/pages', pageBody);
327
+ // If content is provided, add it to the page
328
+ if (content) {
329
+ const blocks = NotionAITool.parseContentToBlocks(content);
330
+ if (blocks.length > 0) {
331
+ await NotionUtils_1.notionApiRequest.call(executeFunctions, 'PATCH', `/blocks/${page.id}/children`, {
332
+ children: blocks,
333
+ });
334
+ }
335
+ }
336
+ return {
337
+ pageId: page.id,
338
+ title: pageTitle,
339
+ url: page.url,
340
+ message: `Created page "${pageTitle}" with content`,
341
+ };
342
+ }
343
+ static async addContentToPage(executeFunctions, itemIndex) {
344
+ const targetPageId = executeFunctions.getNodeParameter('targetPageId', itemIndex);
345
+ const content = executeFunctions.getNodeParameter('content', itemIndex);
346
+ const resolvedPageId = await NotionUtils_1.resolvePageId.call(executeFunctions, targetPageId);
347
+ const blocks = NotionAITool.parseContentToBlocks(content);
348
+ if (blocks.length === 0) {
349
+ throw new n8n_workflow_1.NodeOperationError(executeFunctions.getNode(), 'No valid content blocks found to add');
350
+ }
351
+ const result = await NotionUtils_1.notionApiRequest.call(executeFunctions, 'PATCH', `/blocks/${resolvedPageId}/children`, {
352
+ children: blocks,
353
+ });
354
+ return {
355
+ pageId: resolvedPageId,
356
+ blocksAdded: blocks.length,
357
+ message: `Added ${blocks.length} content blocks to page`,
358
+ result,
359
+ };
360
+ }
361
+ static async searchPages(executeFunctions, itemIndex) {
362
+ var _a, _b;
363
+ const searchQuery = executeFunctions.getNodeParameter('searchQuery', itemIndex, '');
364
+ const additionalOptions = executeFunctions.getNodeParameter('additionalOptions', itemIndex, {});
365
+ const maxResults = additionalOptions.maxResults || 20;
366
+ const body = {
367
+ page_size: Math.min(maxResults, 100),
368
+ };
369
+ if (searchQuery) {
370
+ body.query = searchQuery;
371
+ }
372
+ body.filter = {
373
+ property: 'object',
374
+ value: 'page',
375
+ };
376
+ const response = await NotionUtils_1.notionApiRequest.call(executeFunctions, 'POST', '/search', body);
377
+ return {
378
+ totalResults: ((_a = response.results) === null || _a === void 0 ? void 0 : _a.length) || 0,
379
+ pages: response.results || [],
380
+ message: `Found ${((_b = response.results) === null || _b === void 0 ? void 0 : _b.length) || 0} pages`,
381
+ };
382
+ }
383
+ static async updatePageProperties(executeFunctions, itemIndex) {
384
+ const targetPageId = executeFunctions.getNodeParameter('targetPageId', itemIndex);
385
+ const propertiesToUpdate = executeFunctions.getNodeParameter('propertiesToUpdate', itemIndex);
386
+ const resolvedPageId = await NotionUtils_1.resolvePageId.call(executeFunctions, targetPageId);
387
+ const properties = NotionAITool.parsePropertiesToUpdate(propertiesToUpdate);
388
+ const result = await NotionUtils_1.notionApiRequest.call(executeFunctions, 'PATCH', `/pages/${resolvedPageId}`, {
389
+ properties,
390
+ });
391
+ return {
392
+ pageId: resolvedPageId,
393
+ updatedProperties: Object.keys(properties),
394
+ message: `Updated ${Object.keys(properties).length} properties`,
395
+ result,
396
+ };
397
+ }
398
+ static async createDatabaseEntry(executeFunctions, itemIndex) {
399
+ const parentId = executeFunctions.getNodeParameter('parentId', itemIndex);
400
+ const entryProperties = executeFunctions.getNodeParameter('entryProperties', itemIndex);
401
+ const resolvedParentId = await NotionUtils_1.resolvePageId.call(executeFunctions, parentId);
402
+ const properties = NotionAITool.parsePropertiesToUpdate(entryProperties);
403
+ const result = await NotionUtils_1.notionApiRequest.call(executeFunctions, 'POST', '/pages', {
404
+ parent: { database_id: resolvedParentId },
405
+ properties,
406
+ });
407
+ return {
408
+ entryId: result.id,
409
+ databaseId: resolvedParentId,
410
+ message: 'Created new database entry',
411
+ result,
412
+ };
413
+ }
414
+ static async queryDatabase(executeFunctions, itemIndex) {
415
+ var _a, _b;
416
+ const databaseId = executeFunctions.getNodeParameter('databaseId', itemIndex);
417
+ const queryFilter = executeFunctions.getNodeParameter('queryFilter', itemIndex, '');
418
+ const additionalOptions = executeFunctions.getNodeParameter('additionalOptions', itemIndex, {});
419
+ const maxResults = additionalOptions.maxResults || 20;
420
+ const resolvedDatabaseId = await NotionUtils_1.resolvePageId.call(executeFunctions, databaseId);
421
+ const body = {
422
+ page_size: Math.min(maxResults, 100),
423
+ };
424
+ if (queryFilter) {
425
+ try {
426
+ body.filter = JSON.parse(queryFilter);
427
+ }
428
+ catch {
429
+ // If not JSON, create a simple text filter
430
+ body.filter = {
431
+ property: 'Name',
432
+ title: {
433
+ contains: queryFilter,
434
+ },
435
+ };
436
+ }
437
+ }
438
+ const response = await NotionUtils_1.notionApiRequest.call(executeFunctions, 'POST', `/databases/${resolvedDatabaseId}/query`, body);
439
+ return {
440
+ databaseId: resolvedDatabaseId,
441
+ totalResults: ((_a = response.results) === null || _a === void 0 ? void 0 : _a.length) || 0,
442
+ entries: response.results || [],
443
+ message: `Found ${((_b = response.results) === null || _b === void 0 ? void 0 : _b.length) || 0} database entries`,
444
+ };
445
+ }
446
+ static parseContentToBlocks(content) {
447
+ const blocks = [];
448
+ const lines = content.split('\n');
449
+ for (let i = 0; i < lines.length; i++) {
450
+ const line = lines[i].trim();
451
+ if (!line)
452
+ continue;
453
+ // Parse different content types
454
+ if (line.startsWith('# ')) {
455
+ blocks.push({
456
+ object: 'block',
457
+ type: 'heading_1',
458
+ heading_1: {
459
+ rich_text: [(0, NotionUtils_1.createRichText)(line.substring(2))],
460
+ },
461
+ });
462
+ }
463
+ else if (line.startsWith('## ')) {
464
+ blocks.push({
465
+ object: 'block',
466
+ type: 'heading_2',
467
+ heading_2: {
468
+ rich_text: [(0, NotionUtils_1.createRichText)(line.substring(3))],
469
+ },
470
+ });
471
+ }
472
+ else if (line.startsWith('### ')) {
473
+ blocks.push({
474
+ object: 'block',
475
+ type: 'heading_3',
476
+ heading_3: {
477
+ rich_text: [(0, NotionUtils_1.createRichText)(line.substring(4))],
478
+ },
479
+ });
480
+ }
481
+ else if (line.startsWith('- ') || line.startsWith('* ')) {
482
+ blocks.push({
483
+ object: 'block',
484
+ type: 'bulleted_list_item',
485
+ bulleted_list_item: {
486
+ rich_text: [(0, NotionUtils_1.createRichText)(line.substring(2))],
487
+ },
488
+ });
489
+ }
490
+ else if (line.match(/^\d+\. /)) {
491
+ blocks.push({
492
+ object: 'block',
493
+ type: 'numbered_list_item',
494
+ numbered_list_item: {
495
+ rich_text: [(0, NotionUtils_1.createRichText)(line.replace(/^\d+\. /, ''))],
496
+ },
497
+ });
498
+ }
499
+ else if (line.startsWith('> ')) {
500
+ blocks.push({
501
+ object: 'block',
502
+ type: 'quote',
503
+ quote: {
504
+ rich_text: [(0, NotionUtils_1.createRichText)(line.substring(2))],
505
+ },
506
+ });
507
+ }
508
+ else if (line.startsWith('```')) {
509
+ // Handle code blocks
510
+ const codeLines = [];
511
+ i++; // Skip the opening ```
512
+ while (i < lines.length && !lines[i].trim().startsWith('```')) {
513
+ codeLines.push(lines[i]);
514
+ i++;
515
+ }
516
+ blocks.push({
517
+ object: 'block',
518
+ type: 'code',
519
+ code: {
520
+ rich_text: [(0, NotionUtils_1.createRichText)(codeLines.join('\n'))],
521
+ language: 'plain text',
522
+ },
523
+ });
524
+ }
525
+ else {
526
+ // Regular paragraph
527
+ blocks.push({
528
+ object: 'block',
529
+ type: 'paragraph',
530
+ paragraph: {
531
+ rich_text: [(0, NotionUtils_1.createRichText)(line)],
532
+ },
533
+ });
534
+ }
535
+ }
536
+ return blocks;
537
+ }
538
+ static parsePropertiesToUpdate(propertiesString) {
539
+ try {
540
+ // Try to parse as JSON first
541
+ return JSON.parse(propertiesString);
542
+ }
543
+ catch {
544
+ // If not JSON, try to parse natural language
545
+ const properties = {};
546
+ // Simple natural language parsing
547
+ const patterns = [
548
+ /set\s+(\w+)\s+to\s+(.+?)(?:\s+and|$)/gi,
549
+ /(\w+)\s*:\s*(.+?)(?:\s*,|$)/gi,
550
+ /(\w+)\s*=\s*(.+?)(?:\s*,|$)/gi,
551
+ ];
552
+ for (const pattern of patterns) {
553
+ let match;
554
+ while ((match = pattern.exec(propertiesString)) !== null) {
555
+ const [, key, value] = match;
556
+ properties[key.trim()] = {
557
+ rich_text: [(0, NotionUtils_1.createRichText)(value.trim())],
558
+ };
559
+ }
560
+ }
561
+ return properties;
562
+ }
563
+ }
564
+ }
565
+ exports.NotionAITool = NotionAITool;
@@ -34,8 +34,8 @@ class NotionAdvanced {
34
34
  defaults: {
35
35
  name: 'Notion Advanced',
36
36
  },
37
- inputs: ['main'],
38
- outputs: ['main'],
37
+ inputs: ["main" /* NodeConnectionType.Main */],
38
+ outputs: ["main" /* NodeConnectionType.Main */],
39
39
  credentials: [
40
40
  {
41
41
  name: 'notionApi',
@@ -37,7 +37,7 @@ async function notionApiRequest(method, endpoint, body = {}, qs = {}) {
37
37
  'Notion-Version': '2022-06-28',
38
38
  'Content-Type': 'application/json',
39
39
  },
40
- uri: `https://api.notion.com/v1${endpoint}`,
40
+ url: `https://api.notion.com/v1${endpoint}`,
41
41
  body,
42
42
  qs,
43
43
  json: true,
package/dist/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "n8n-nodes-notion-advanced",
3
- "version": "1.1.18-beta",
3
+ "version": "1.1.19-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": "node dev-notes/build-for-install.js",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "n8n-nodes-notion-advanced",
3
- "version": "1.1.18-beta",
3
+ "version": "1.1.19-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": "node dev-notes/build-for-install.js",