n8n-nodes-notion-advanced 1.2.3-beta → 1.2.4-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.
- package/nodes/NotionAdvanced/NotionAITool.node.d.ts +18 -0
- package/nodes/NotionAdvanced/NotionAITool.node.js +1154 -0
- package/nodes/NotionAdvanced/NotionAITool.node.ts +611 -0
- package/nodes/NotionAdvanced/NotionAdvanced.node.d.ts +25 -0
- package/nodes/NotionAdvanced/NotionAdvanced.node.js +905 -0
- package/nodes/NotionAdvanced/NotionAdvanced.node.ts +1022 -0
- package/nodes/NotionAdvanced/NotionUtils.d.ts +104 -0
- package/nodes/NotionAdvanced/NotionUtils.js +465 -0
- package/nodes/NotionAdvanced/NotionUtils.ts +588 -0
- package/nodes/NotionAdvanced/notion.svg +3 -0
- package/package.json +5 -6
- package/types/NotionTypes.d.ts +359 -0
- package/types/NotionTypes.js +3 -0
- package/types/NotionTypes.ts +411 -0
@@ -0,0 +1,1022 @@
|
|
1
|
+
import {
|
2
|
+
IExecuteFunctions,
|
3
|
+
INodeExecutionData,
|
4
|
+
INodeType,
|
5
|
+
INodeTypeDescription,
|
6
|
+
IDataObject,
|
7
|
+
NodeOperationError,
|
8
|
+
} from 'n8n-workflow';
|
9
|
+
|
10
|
+
import {
|
11
|
+
notionApiRequest,
|
12
|
+
validateCredentials,
|
13
|
+
parseRichTextInput,
|
14
|
+
convertBlockInput,
|
15
|
+
resolvePageId,
|
16
|
+
validateBlock,
|
17
|
+
paginatedRequest,
|
18
|
+
createRichText,
|
19
|
+
createPageInput,
|
20
|
+
getBlocksWithIds,
|
21
|
+
createExecutionData,
|
22
|
+
// Block creation functions - used indirectly via convertBlockInput
|
23
|
+
createParagraphBlock,
|
24
|
+
createHeadingBlock,
|
25
|
+
createListItemBlock,
|
26
|
+
createToDoBlock,
|
27
|
+
createCodeBlock,
|
28
|
+
createQuoteBlock,
|
29
|
+
createCalloutBlock,
|
30
|
+
createDividerBlock,
|
31
|
+
createEquationBlock,
|
32
|
+
createImageBlock,
|
33
|
+
createBookmarkBlock,
|
34
|
+
createEmbedBlock,
|
35
|
+
createTableBlock,
|
36
|
+
} from './NotionUtils';
|
37
|
+
|
38
|
+
import type {
|
39
|
+
Block,
|
40
|
+
BlockInput,
|
41
|
+
BlockWithId,
|
42
|
+
NotionPage,
|
43
|
+
NotionApiResponse,
|
44
|
+
NotionBlockChildrenResponse,
|
45
|
+
NotionSearchResponse,
|
46
|
+
PageInput,
|
47
|
+
} from '../../types/NotionTypes';
|
48
|
+
|
49
|
+
// Ensure all block creation functions are available for dynamic usage
|
50
|
+
const blockCreators = {
|
51
|
+
createParagraphBlock,
|
52
|
+
createHeadingBlock,
|
53
|
+
createListItemBlock,
|
54
|
+
createToDoBlock,
|
55
|
+
createCodeBlock,
|
56
|
+
createQuoteBlock,
|
57
|
+
createCalloutBlock,
|
58
|
+
createDividerBlock,
|
59
|
+
createEquationBlock,
|
60
|
+
createImageBlock,
|
61
|
+
createBookmarkBlock,
|
62
|
+
createEmbedBlock,
|
63
|
+
createTableBlock,
|
64
|
+
};
|
65
|
+
|
66
|
+
// Prevent unused variable warning
|
67
|
+
void blockCreators;
|
68
|
+
|
69
|
+
export class NotionAdvanced implements INodeType {
|
70
|
+
description: INodeTypeDescription = {
|
71
|
+
displayName: 'Notion Advanced',
|
72
|
+
name: 'notionAdvanced',
|
73
|
+
icon: 'file:notion.svg',
|
74
|
+
group: ['productivity'],
|
75
|
+
version: 1,
|
76
|
+
subtitle: '={{$parameter["operation"] + ": " + $parameter["resource"]}}',
|
77
|
+
description: 'Full-featured Notion node with exhaustive block and formatting support using existing credentials',
|
78
|
+
defaults: {
|
79
|
+
name: 'Notion Advanced',
|
80
|
+
},
|
81
|
+
inputs: ['main'],
|
82
|
+
outputs: ['main'],
|
83
|
+
credentials: [
|
84
|
+
{
|
85
|
+
name: 'notionApi',
|
86
|
+
required: true,
|
87
|
+
},
|
88
|
+
],
|
89
|
+
properties: [
|
90
|
+
{
|
91
|
+
displayName: 'Resource',
|
92
|
+
name: 'resource',
|
93
|
+
type: 'options',
|
94
|
+
noDataExpression: true,
|
95
|
+
options: [
|
96
|
+
{
|
97
|
+
name: 'Page',
|
98
|
+
value: 'page',
|
99
|
+
},
|
100
|
+
{
|
101
|
+
name: 'Block',
|
102
|
+
value: 'block',
|
103
|
+
},
|
104
|
+
{
|
105
|
+
name: 'Database',
|
106
|
+
value: 'database',
|
107
|
+
},
|
108
|
+
{
|
109
|
+
name: 'User',
|
110
|
+
value: 'user',
|
111
|
+
},
|
112
|
+
],
|
113
|
+
default: 'page',
|
114
|
+
},
|
115
|
+
// PAGE OPERATIONS
|
116
|
+
{
|
117
|
+
displayName: 'Operation',
|
118
|
+
name: 'operation',
|
119
|
+
type: 'options',
|
120
|
+
noDataExpression: true,
|
121
|
+
displayOptions: {
|
122
|
+
show: {
|
123
|
+
resource: ['page'],
|
124
|
+
},
|
125
|
+
},
|
126
|
+
options: [
|
127
|
+
{
|
128
|
+
name: 'Create',
|
129
|
+
value: 'create',
|
130
|
+
description: 'Create a new page',
|
131
|
+
action: 'Create a page',
|
132
|
+
},
|
133
|
+
{
|
134
|
+
name: 'Get',
|
135
|
+
value: 'get',
|
136
|
+
description: 'Get a page',
|
137
|
+
action: 'Get a page',
|
138
|
+
},
|
139
|
+
{
|
140
|
+
name: 'Update',
|
141
|
+
value: 'update',
|
142
|
+
description: 'Update page properties',
|
143
|
+
action: 'Update a page',
|
144
|
+
},
|
145
|
+
{
|
146
|
+
name: 'Archive',
|
147
|
+
value: 'archive',
|
148
|
+
description: 'Archive a page',
|
149
|
+
action: 'Archive a page',
|
150
|
+
},
|
151
|
+
{
|
152
|
+
name: 'Search',
|
153
|
+
value: 'search',
|
154
|
+
description: 'Search pages',
|
155
|
+
action: 'Search pages',
|
156
|
+
},
|
157
|
+
],
|
158
|
+
default: 'create',
|
159
|
+
},
|
160
|
+
// BLOCK OPERATIONS
|
161
|
+
{
|
162
|
+
displayName: 'Operation',
|
163
|
+
name: 'operation',
|
164
|
+
type: 'options',
|
165
|
+
noDataExpression: true,
|
166
|
+
displayOptions: {
|
167
|
+
show: {
|
168
|
+
resource: ['block'],
|
169
|
+
},
|
170
|
+
},
|
171
|
+
options: [
|
172
|
+
{
|
173
|
+
name: 'Create',
|
174
|
+
value: 'create',
|
175
|
+
description: 'Create new blocks',
|
176
|
+
action: 'Create blocks',
|
177
|
+
},
|
178
|
+
{
|
179
|
+
name: 'Get',
|
180
|
+
value: 'get',
|
181
|
+
description: 'Get a block',
|
182
|
+
action: 'Get a block',
|
183
|
+
},
|
184
|
+
{
|
185
|
+
name: 'Update',
|
186
|
+
value: 'update',
|
187
|
+
description: 'Update a block',
|
188
|
+
action: 'Update a block',
|
189
|
+
},
|
190
|
+
{
|
191
|
+
name: 'Delete',
|
192
|
+
value: 'delete',
|
193
|
+
description: 'Delete a block',
|
194
|
+
action: 'Delete a block',
|
195
|
+
},
|
196
|
+
{
|
197
|
+
name: 'Get Children',
|
198
|
+
value: 'getChildren',
|
199
|
+
description: 'Get child blocks',
|
200
|
+
action: 'Get child blocks',
|
201
|
+
},
|
202
|
+
{
|
203
|
+
name: 'Append Children',
|
204
|
+
value: 'appendChildren',
|
205
|
+
description: 'Append children to a block',
|
206
|
+
action: 'Append children to a block',
|
207
|
+
},
|
208
|
+
],
|
209
|
+
default: 'create',
|
210
|
+
},
|
211
|
+
// DATABASE OPERATIONS
|
212
|
+
{
|
213
|
+
displayName: 'Operation',
|
214
|
+
name: 'operation',
|
215
|
+
type: 'options',
|
216
|
+
noDataExpression: true,
|
217
|
+
displayOptions: {
|
218
|
+
show: {
|
219
|
+
resource: ['database'],
|
220
|
+
},
|
221
|
+
},
|
222
|
+
options: [
|
223
|
+
{
|
224
|
+
name: 'Get',
|
225
|
+
value: 'get',
|
226
|
+
description: 'Get a database',
|
227
|
+
action: 'Get a database',
|
228
|
+
},
|
229
|
+
{
|
230
|
+
name: 'Query',
|
231
|
+
value: 'query',
|
232
|
+
description: 'Query a database',
|
233
|
+
action: 'Query a database',
|
234
|
+
},
|
235
|
+
{
|
236
|
+
name: 'Create',
|
237
|
+
value: 'create',
|
238
|
+
description: 'Create a database',
|
239
|
+
action: 'Create a database',
|
240
|
+
},
|
241
|
+
],
|
242
|
+
default: 'get',
|
243
|
+
},
|
244
|
+
// USER OPERATIONS
|
245
|
+
{
|
246
|
+
displayName: 'Operation',
|
247
|
+
name: 'operation',
|
248
|
+
type: 'options',
|
249
|
+
noDataExpression: true,
|
250
|
+
displayOptions: {
|
251
|
+
show: {
|
252
|
+
resource: ['user'],
|
253
|
+
},
|
254
|
+
},
|
255
|
+
options: [
|
256
|
+
{
|
257
|
+
name: 'Get',
|
258
|
+
value: 'get',
|
259
|
+
description: 'Get a user',
|
260
|
+
action: 'Get a user',
|
261
|
+
},
|
262
|
+
{
|
263
|
+
name: 'List',
|
264
|
+
value: 'list',
|
265
|
+
description: 'List all users',
|
266
|
+
action: 'List users',
|
267
|
+
},
|
268
|
+
],
|
269
|
+
default: 'get',
|
270
|
+
},
|
271
|
+
|
272
|
+
// PAGE FIELDS
|
273
|
+
{
|
274
|
+
displayName: 'Parent Page/Database',
|
275
|
+
name: 'parent',
|
276
|
+
type: 'string',
|
277
|
+
required: true,
|
278
|
+
displayOptions: {
|
279
|
+
show: {
|
280
|
+
resource: ['page'],
|
281
|
+
operation: ['create'],
|
282
|
+
},
|
283
|
+
},
|
284
|
+
default: '',
|
285
|
+
description: 'Page ID, Database ID, or search term for the parent',
|
286
|
+
},
|
287
|
+
{
|
288
|
+
displayName: 'Page ID',
|
289
|
+
name: 'pageId',
|
290
|
+
type: 'string',
|
291
|
+
required: true,
|
292
|
+
displayOptions: {
|
293
|
+
show: {
|
294
|
+
resource: ['page'],
|
295
|
+
operation: ['get', 'update', 'archive'],
|
296
|
+
},
|
297
|
+
},
|
298
|
+
default: '',
|
299
|
+
description: 'Page ID or URL',
|
300
|
+
},
|
301
|
+
{
|
302
|
+
displayName: 'Title',
|
303
|
+
name: 'title',
|
304
|
+
type: 'string',
|
305
|
+
required: true,
|
306
|
+
displayOptions: {
|
307
|
+
show: {
|
308
|
+
resource: ['page'],
|
309
|
+
operation: ['create'],
|
310
|
+
},
|
311
|
+
},
|
312
|
+
default: '',
|
313
|
+
description: 'Page title',
|
314
|
+
},
|
315
|
+
{
|
316
|
+
displayName: 'Properties',
|
317
|
+
name: 'properties',
|
318
|
+
type: 'fixedCollection',
|
319
|
+
typeOptions: {
|
320
|
+
multipleValues: true,
|
321
|
+
},
|
322
|
+
displayOptions: {
|
323
|
+
show: {
|
324
|
+
resource: ['page'],
|
325
|
+
operation: ['create', 'update'],
|
326
|
+
},
|
327
|
+
},
|
328
|
+
default: {},
|
329
|
+
options: [
|
330
|
+
{
|
331
|
+
name: 'property',
|
332
|
+
displayName: 'Property',
|
333
|
+
values: [
|
334
|
+
{
|
335
|
+
displayName: 'Name',
|
336
|
+
name: 'name',
|
337
|
+
type: 'string',
|
338
|
+
default: '',
|
339
|
+
description: 'Property name',
|
340
|
+
},
|
341
|
+
{
|
342
|
+
displayName: 'Type',
|
343
|
+
name: 'type',
|
344
|
+
type: 'options',
|
345
|
+
options: [
|
346
|
+
{ name: 'Title', value: 'title' },
|
347
|
+
{ name: 'Rich Text', value: 'rich_text' },
|
348
|
+
{ name: 'Number', value: 'number' },
|
349
|
+
{ name: 'Select', value: 'select' },
|
350
|
+
{ name: 'Multi-select', value: 'multi_select' },
|
351
|
+
{ name: 'Date', value: 'date' },
|
352
|
+
{ name: 'People', value: 'people' },
|
353
|
+
{ name: 'Files', value: 'files' },
|
354
|
+
{ name: 'Checkbox', value: 'checkbox' },
|
355
|
+
{ name: 'URL', value: 'url' },
|
356
|
+
{ name: 'Email', value: 'email' },
|
357
|
+
{ name: 'Phone', value: 'phone_number' },
|
358
|
+
{ name: 'Formula', value: 'formula' },
|
359
|
+
{ name: 'Relation', value: 'relation' },
|
360
|
+
{ name: 'Rollup', value: 'rollup' },
|
361
|
+
{ name: 'Created Time', value: 'created_time' },
|
362
|
+
{ name: 'Created By', value: 'created_by' },
|
363
|
+
{ name: 'Last Edited Time', value: 'last_edited_time' },
|
364
|
+
{ name: 'Last Edited By', value: 'last_edited_by' },
|
365
|
+
],
|
366
|
+
default: 'rich_text',
|
367
|
+
},
|
368
|
+
{
|
369
|
+
displayName: 'Value',
|
370
|
+
name: 'value',
|
371
|
+
type: 'string',
|
372
|
+
default: '',
|
373
|
+
description: 'Property value (JSON for complex types)',
|
374
|
+
},
|
375
|
+
],
|
376
|
+
},
|
377
|
+
],
|
378
|
+
},
|
379
|
+
|
380
|
+
// BLOCK FIELDS
|
381
|
+
{
|
382
|
+
displayName: 'Block ID',
|
383
|
+
name: 'blockId',
|
384
|
+
type: 'string',
|
385
|
+
required: true,
|
386
|
+
displayOptions: {
|
387
|
+
show: {
|
388
|
+
resource: ['block'],
|
389
|
+
operation: ['get', 'update', 'delete', 'getChildren', 'appendChildren'],
|
390
|
+
},
|
391
|
+
},
|
392
|
+
default: '',
|
393
|
+
description: 'Block ID',
|
394
|
+
},
|
395
|
+
{
|
396
|
+
displayName: 'Parent ID',
|
397
|
+
name: 'parentId',
|
398
|
+
type: 'string',
|
399
|
+
required: true,
|
400
|
+
displayOptions: {
|
401
|
+
show: {
|
402
|
+
resource: ['block'],
|
403
|
+
operation: ['create'],
|
404
|
+
},
|
405
|
+
},
|
406
|
+
default: '',
|
407
|
+
description: 'Parent page or block ID',
|
408
|
+
},
|
409
|
+
{
|
410
|
+
displayName: 'Blocks',
|
411
|
+
name: 'blocks',
|
412
|
+
type: 'fixedCollection',
|
413
|
+
typeOptions: {
|
414
|
+
multipleValues: true,
|
415
|
+
},
|
416
|
+
displayOptions: {
|
417
|
+
show: {
|
418
|
+
resource: ['block'],
|
419
|
+
operation: ['create', 'appendChildren'],
|
420
|
+
},
|
421
|
+
},
|
422
|
+
default: {},
|
423
|
+
options: [
|
424
|
+
{
|
425
|
+
name: 'block',
|
426
|
+
displayName: 'Block',
|
427
|
+
values: [
|
428
|
+
{
|
429
|
+
displayName: 'Type',
|
430
|
+
name: 'type',
|
431
|
+
type: 'options',
|
432
|
+
options: [
|
433
|
+
{ name: 'Paragraph', value: 'paragraph' },
|
434
|
+
{ name: 'Heading 1', value: 'heading_1' },
|
435
|
+
{ name: 'Heading 2', value: 'heading_2' },
|
436
|
+
{ name: 'Heading 3', value: 'heading_3' },
|
437
|
+
{ name: 'Bulleted List Item', value: 'bulleted_list_item' },
|
438
|
+
{ name: 'Numbered List Item', value: 'numbered_list_item' },
|
439
|
+
{ name: 'To Do', value: 'to_do' },
|
440
|
+
{ name: 'Toggle', value: 'toggle' },
|
441
|
+
{ name: 'Quote', value: 'quote' },
|
442
|
+
{ name: 'Callout', value: 'callout' },
|
443
|
+
{ name: 'Code', value: 'code' },
|
444
|
+
{ name: 'Divider', value: 'divider' },
|
445
|
+
{ name: 'Image', value: 'image' },
|
446
|
+
{ name: 'Video', value: 'video' },
|
447
|
+
{ name: 'Audio', value: 'audio' },
|
448
|
+
{ name: 'File', value: 'file' },
|
449
|
+
{ name: 'PDF', value: 'pdf' },
|
450
|
+
{ name: 'Bookmark', value: 'bookmark' },
|
451
|
+
{ name: 'Embed', value: 'embed' },
|
452
|
+
{ name: 'Link Preview', value: 'link_preview' },
|
453
|
+
{ name: 'Equation', value: 'equation' },
|
454
|
+
{ name: 'Table', value: 'table' },
|
455
|
+
{ name: 'Column List', value: 'column_list' },
|
456
|
+
{ name: 'Synced Block', value: 'synced_block' },
|
457
|
+
{ name: 'Template', value: 'template' },
|
458
|
+
{ name: 'Table of Contents', value: 'table_of_contents' },
|
459
|
+
],
|
460
|
+
default: 'paragraph',
|
461
|
+
},
|
462
|
+
{
|
463
|
+
displayName: 'Content',
|
464
|
+
name: 'content',
|
465
|
+
type: 'string',
|
466
|
+
default: '',
|
467
|
+
description: 'Block content (text, code, URL, etc.)',
|
468
|
+
},
|
469
|
+
{
|
470
|
+
displayName: 'Rich Text (JSON)',
|
471
|
+
name: 'richText',
|
472
|
+
type: 'string',
|
473
|
+
default: '',
|
474
|
+
description: 'Rich text as JSON array with formatting',
|
475
|
+
},
|
476
|
+
{
|
477
|
+
displayName: 'Properties (JSON)',
|
478
|
+
name: 'properties',
|
479
|
+
type: 'string',
|
480
|
+
default: '{}',
|
481
|
+
description: 'Block properties as JSON (color, checked, language, etc.)',
|
482
|
+
},
|
483
|
+
{
|
484
|
+
displayName: 'Children (JSON)',
|
485
|
+
name: 'children',
|
486
|
+
type: 'string',
|
487
|
+
default: '',
|
488
|
+
description: 'Child blocks as JSON array',
|
489
|
+
},
|
490
|
+
],
|
491
|
+
},
|
492
|
+
],
|
493
|
+
},
|
494
|
+
|
495
|
+
// SEARCH FIELDS
|
496
|
+
{
|
497
|
+
displayName: 'Search Query',
|
498
|
+
name: 'query',
|
499
|
+
type: 'string',
|
500
|
+
displayOptions: {
|
501
|
+
show: {
|
502
|
+
resource: ['page'],
|
503
|
+
operation: ['search'],
|
504
|
+
},
|
505
|
+
},
|
506
|
+
default: '',
|
507
|
+
description: 'Search query',
|
508
|
+
},
|
509
|
+
{
|
510
|
+
displayName: 'Filter',
|
511
|
+
name: 'filter',
|
512
|
+
type: 'string',
|
513
|
+
displayOptions: {
|
514
|
+
show: {
|
515
|
+
resource: ['page'],
|
516
|
+
operation: ['search'],
|
517
|
+
},
|
518
|
+
},
|
519
|
+
default: '',
|
520
|
+
description: 'Search filter as JSON',
|
521
|
+
},
|
522
|
+
|
523
|
+
// DATABASE FIELDS
|
524
|
+
{
|
525
|
+
displayName: 'Database ID',
|
526
|
+
name: 'databaseId',
|
527
|
+
type: 'string',
|
528
|
+
required: true,
|
529
|
+
displayOptions: {
|
530
|
+
show: {
|
531
|
+
resource: ['database'],
|
532
|
+
operation: ['get', 'query'],
|
533
|
+
},
|
534
|
+
},
|
535
|
+
default: '',
|
536
|
+
description: 'Database ID',
|
537
|
+
},
|
538
|
+
|
539
|
+
// USER FIELDS
|
540
|
+
{
|
541
|
+
displayName: 'User ID',
|
542
|
+
name: 'userId',
|
543
|
+
type: 'string',
|
544
|
+
required: true,
|
545
|
+
displayOptions: {
|
546
|
+
show: {
|
547
|
+
resource: ['user'],
|
548
|
+
operation: ['get'],
|
549
|
+
},
|
550
|
+
},
|
551
|
+
default: '',
|
552
|
+
description: 'User ID',
|
553
|
+
},
|
554
|
+
|
555
|
+
// COMMON OPTIONS
|
556
|
+
{
|
557
|
+
displayName: 'Additional Fields',
|
558
|
+
name: 'additionalFields',
|
559
|
+
type: 'collection',
|
560
|
+
placeholder: 'Add Field',
|
561
|
+
default: {},
|
562
|
+
options: [
|
563
|
+
{
|
564
|
+
displayName: 'Icon',
|
565
|
+
name: 'icon',
|
566
|
+
type: 'string',
|
567
|
+
default: '',
|
568
|
+
description: 'Page icon (emoji or image URL)',
|
569
|
+
},
|
570
|
+
{
|
571
|
+
displayName: 'Cover',
|
572
|
+
name: 'cover',
|
573
|
+
type: 'string',
|
574
|
+
default: '',
|
575
|
+
description: 'Page cover image URL',
|
576
|
+
},
|
577
|
+
{
|
578
|
+
displayName: 'Archive',
|
579
|
+
name: 'archived',
|
580
|
+
type: 'boolean',
|
581
|
+
default: false,
|
582
|
+
description: 'Whether to archive the page',
|
583
|
+
},
|
584
|
+
],
|
585
|
+
},
|
586
|
+
],
|
587
|
+
};
|
588
|
+
|
589
|
+
async execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]> {
|
590
|
+
const items = this.getInputData();
|
591
|
+
let responseData: IDataObject[] = [];
|
592
|
+
|
593
|
+
// Validate credentials first
|
594
|
+
const isValid = await validateCredentials.call(this);
|
595
|
+
if (!isValid) {
|
596
|
+
throw new NodeOperationError(this.getNode(), 'Invalid Notion API credentials');
|
597
|
+
}
|
598
|
+
|
599
|
+
for (let i = 0; i < items.length; i++) {
|
600
|
+
try {
|
601
|
+
const resource = this.getNodeParameter('resource', i) as string;
|
602
|
+
const operation = this.getNodeParameter('operation', i) as string;
|
603
|
+
|
604
|
+
let item: IDataObject;
|
605
|
+
|
606
|
+
if (resource === 'page') {
|
607
|
+
item = await this.executePage(this, operation, i);
|
608
|
+
} else if (resource === 'block') {
|
609
|
+
item = await this.executeBlock(this, operation, i);
|
610
|
+
} else if (resource === 'database') {
|
611
|
+
item = await this.executeDatabase(this, operation, i);
|
612
|
+
} else if (resource === 'user') {
|
613
|
+
item = await this.executeUser(this, operation, i);
|
614
|
+
} else {
|
615
|
+
throw new NodeOperationError(this.getNode(), `Unknown resource: ${resource}`);
|
616
|
+
}
|
617
|
+
|
618
|
+
responseData.push(item);
|
619
|
+
} catch (error) {
|
620
|
+
if (this.continueOnFail()) {
|
621
|
+
responseData.push({ error: (error as Error).message });
|
622
|
+
} else {
|
623
|
+
throw error;
|
624
|
+
}
|
625
|
+
}
|
626
|
+
}
|
627
|
+
|
628
|
+
// Convert to proper execution data format
|
629
|
+
const executionData = createExecutionData(responseData);
|
630
|
+
return [executionData];
|
631
|
+
}
|
632
|
+
|
633
|
+
private async executePage(executeFunctions: IExecuteFunctions, operation: string, itemIndex: number): Promise<IDataObject> {
|
634
|
+
switch (operation) {
|
635
|
+
case 'create':
|
636
|
+
return this.createPage(executeFunctions, itemIndex);
|
637
|
+
case 'get':
|
638
|
+
return this.getPage(executeFunctions, itemIndex);
|
639
|
+
case 'update':
|
640
|
+
return this.updatePage(executeFunctions, itemIndex);
|
641
|
+
case 'archive':
|
642
|
+
return this.archivePage(executeFunctions, itemIndex);
|
643
|
+
case 'search':
|
644
|
+
return this.searchPages(executeFunctions, itemIndex);
|
645
|
+
default:
|
646
|
+
throw new NodeOperationError(executeFunctions.getNode(), `Unknown page operation: ${operation}`);
|
647
|
+
}
|
648
|
+
}
|
649
|
+
|
650
|
+
private async executeBlock(executeFunctions: IExecuteFunctions, operation: string, itemIndex: number): Promise<IDataObject> {
|
651
|
+
switch (operation) {
|
652
|
+
case 'create':
|
653
|
+
return this.createBlocks(executeFunctions, itemIndex);
|
654
|
+
case 'get':
|
655
|
+
return this.getBlock(executeFunctions, itemIndex);
|
656
|
+
case 'update':
|
657
|
+
return this.updateBlock(executeFunctions, itemIndex);
|
658
|
+
case 'delete':
|
659
|
+
return this.deleteBlock(executeFunctions, itemIndex);
|
660
|
+
case 'getChildren':
|
661
|
+
return this.getBlockChildren(executeFunctions, itemIndex);
|
662
|
+
case 'appendChildren':
|
663
|
+
return this.appendBlockChildren(executeFunctions, itemIndex);
|
664
|
+
default:
|
665
|
+
throw new NodeOperationError(executeFunctions.getNode(), `Unknown block operation: ${operation}`);
|
666
|
+
}
|
667
|
+
}
|
668
|
+
|
669
|
+
private async executeDatabase(executeFunctions: IExecuteFunctions, operation: string, itemIndex: number): Promise<IDataObject> {
|
670
|
+
switch (operation) {
|
671
|
+
case 'get':
|
672
|
+
return this.getDatabase(executeFunctions, itemIndex);
|
673
|
+
case 'query':
|
674
|
+
return this.queryDatabase(executeFunctions, itemIndex);
|
675
|
+
case 'create':
|
676
|
+
return this.createDatabase(executeFunctions, itemIndex);
|
677
|
+
default:
|
678
|
+
throw new NodeOperationError(executeFunctions.getNode(), `Unknown database operation: ${operation}`);
|
679
|
+
}
|
680
|
+
}
|
681
|
+
|
682
|
+
private async executeUser(executeFunctions: IExecuteFunctions, operation: string, itemIndex: number): Promise<IDataObject> {
|
683
|
+
switch (operation) {
|
684
|
+
case 'get':
|
685
|
+
return this.getUser(executeFunctions, itemIndex);
|
686
|
+
case 'list':
|
687
|
+
return this.listUsers(executeFunctions, itemIndex);
|
688
|
+
default:
|
689
|
+
throw new NodeOperationError(executeFunctions.getNode(), `Unknown user operation: ${operation}`);
|
690
|
+
}
|
691
|
+
}
|
692
|
+
|
693
|
+
// PAGE OPERATIONS
|
694
|
+
private async createPage(executeFunctions: IExecuteFunctions, itemIndex: number): Promise<IDataObject> {
|
695
|
+
const parent = executeFunctions.getNodeParameter('parent', itemIndex) as string;
|
696
|
+
const title = executeFunctions.getNodeParameter('title', itemIndex) as string;
|
697
|
+
const properties = executeFunctions.getNodeParameter('properties', itemIndex, {}) as IDataObject;
|
698
|
+
const additionalFields = executeFunctions.getNodeParameter('additionalFields', itemIndex, {}) as IDataObject;
|
699
|
+
|
700
|
+
// Create structured page input for validation
|
701
|
+
const pageInput: PageInput = createPageInput(
|
702
|
+
title,
|
703
|
+
parent,
|
704
|
+
properties,
|
705
|
+
undefined,
|
706
|
+
additionalFields.icon as string,
|
707
|
+
additionalFields.cover as string,
|
708
|
+
);
|
709
|
+
|
710
|
+
const parentId = await resolvePageId.call(executeFunctions, pageInput.parent);
|
711
|
+
|
712
|
+
const body: IDataObject = {
|
713
|
+
parent: { page_id: parentId },
|
714
|
+
properties: {
|
715
|
+
title: {
|
716
|
+
title: [createRichText(pageInput.title)],
|
717
|
+
},
|
718
|
+
},
|
719
|
+
};
|
720
|
+
|
721
|
+
// Add additional properties
|
722
|
+
if (properties.property && Array.isArray(properties.property)) {
|
723
|
+
for (const prop of properties.property) {
|
724
|
+
const { name, type, value } = prop;
|
725
|
+
try {
|
726
|
+
const parsedValue = JSON.parse(value);
|
727
|
+
body.properties[name] = { [type]: parsedValue };
|
728
|
+
} catch {
|
729
|
+
if (type === 'rich_text') {
|
730
|
+
body.properties[name] = { rich_text: [createRichText(value)] };
|
731
|
+
} else {
|
732
|
+
body.properties[name] = { [type]: value };
|
733
|
+
}
|
734
|
+
}
|
735
|
+
}
|
736
|
+
}
|
737
|
+
|
738
|
+
// Add icon and cover if provided
|
739
|
+
if (additionalFields.icon) {
|
740
|
+
body.icon = { type: 'emoji', emoji: additionalFields.icon as string };
|
741
|
+
}
|
742
|
+
if (additionalFields.cover) {
|
743
|
+
body.cover = { type: 'external', external: { url: additionalFields.cover as string } };
|
744
|
+
}
|
745
|
+
|
746
|
+
return await notionApiRequest.call(executeFunctions, 'POST', '/pages', body);
|
747
|
+
}
|
748
|
+
|
749
|
+
private async getPage(executeFunctions: IExecuteFunctions, itemIndex: number): Promise<IDataObject> {
|
750
|
+
const pageId = executeFunctions.getNodeParameter('pageId', itemIndex) as string;
|
751
|
+
const resolvedId = await resolvePageId.call(executeFunctions, pageId);
|
752
|
+
|
753
|
+
const page: NotionPage = await notionApiRequest.call(executeFunctions, 'GET', `/pages/${resolvedId}`);
|
754
|
+
return page;
|
755
|
+
}
|
756
|
+
|
757
|
+
private async updatePage(executeFunctions: IExecuteFunctions, itemIndex: number): Promise<IDataObject> {
|
758
|
+
const pageId = executeFunctions.getNodeParameter('pageId', itemIndex) as string;
|
759
|
+
const properties = executeFunctions.getNodeParameter('properties', itemIndex, {}) as IDataObject;
|
760
|
+
const additionalFields = executeFunctions.getNodeParameter('additionalFields', itemIndex, {}) as IDataObject;
|
761
|
+
|
762
|
+
const resolvedId = await resolvePageId.call(executeFunctions, pageId);
|
763
|
+
|
764
|
+
const body: IDataObject = { properties: {} };
|
765
|
+
|
766
|
+
// Add properties
|
767
|
+
if (properties.property && Array.isArray(properties.property)) {
|
768
|
+
for (const prop of properties.property) {
|
769
|
+
const { name, type, value } = prop;
|
770
|
+
try {
|
771
|
+
const parsedValue = JSON.parse(value);
|
772
|
+
body.properties[name] = { [type]: parsedValue };
|
773
|
+
} catch {
|
774
|
+
if (type === 'rich_text') {
|
775
|
+
body.properties[name] = { rich_text: [createRichText(value)] };
|
776
|
+
} else {
|
777
|
+
body.properties[name] = { [type]: value };
|
778
|
+
}
|
779
|
+
}
|
780
|
+
}
|
781
|
+
}
|
782
|
+
|
783
|
+
// Add archived flag if provided
|
784
|
+
if (additionalFields.archived !== undefined) {
|
785
|
+
body.archived = additionalFields.archived;
|
786
|
+
}
|
787
|
+
|
788
|
+
return await notionApiRequest.call(executeFunctions, 'PATCH', `/pages/${resolvedId}`, body);
|
789
|
+
}
|
790
|
+
|
791
|
+
private async archivePage(executeFunctions: IExecuteFunctions, itemIndex: number): Promise<IDataObject> {
|
792
|
+
const pageId = executeFunctions.getNodeParameter('pageId', itemIndex) as string;
|
793
|
+
const resolvedId = await resolvePageId.call(executeFunctions, pageId);
|
794
|
+
|
795
|
+
return await notionApiRequest.call(executeFunctions, 'PATCH', `/pages/${resolvedId}`, {
|
796
|
+
archived: true,
|
797
|
+
});
|
798
|
+
}
|
799
|
+
|
800
|
+
private async searchPages(executeFunctions: IExecuteFunctions, itemIndex: number): Promise<IDataObject> {
|
801
|
+
const query = executeFunctions.getNodeParameter('query', itemIndex, '') as string;
|
802
|
+
const filter = executeFunctions.getNodeParameter('filter', itemIndex, '') as string;
|
803
|
+
|
804
|
+
const body: IDataObject = {};
|
805
|
+
|
806
|
+
if (query) {
|
807
|
+
body.query = query;
|
808
|
+
}
|
809
|
+
|
810
|
+
if (filter) {
|
811
|
+
try {
|
812
|
+
body.filter = JSON.parse(filter);
|
813
|
+
} catch {
|
814
|
+
body.filter = { property: 'object', value: 'page' };
|
815
|
+
}
|
816
|
+
} else {
|
817
|
+
body.filter = { property: 'object', value: 'page' };
|
818
|
+
}
|
819
|
+
|
820
|
+
const results = await paginatedRequest.call(executeFunctions, 'POST', '/search', body);
|
821
|
+
const searchResponse: NotionSearchResponse = {
|
822
|
+
object: 'list',
|
823
|
+
results,
|
824
|
+
count: results.length
|
825
|
+
};
|
826
|
+
return searchResponse;
|
827
|
+
}
|
828
|
+
|
829
|
+
// BLOCK OPERATIONS
|
830
|
+
private async createBlocks(executeFunctions: IExecuteFunctions, itemIndex: number): Promise<IDataObject> {
|
831
|
+
const parentId = executeFunctions.getNodeParameter('parentId', itemIndex) as string;
|
832
|
+
const blocks = executeFunctions.getNodeParameter('blocks', itemIndex, {}) as IDataObject;
|
833
|
+
|
834
|
+
const resolvedParentId = await resolvePageId.call(executeFunctions, parentId);
|
835
|
+
|
836
|
+
if (!blocks.block || !Array.isArray(blocks.block)) {
|
837
|
+
throw new NodeOperationError(executeFunctions.getNode(), 'No blocks provided');
|
838
|
+
}
|
839
|
+
|
840
|
+
const blockData: Block[] = [];
|
841
|
+
|
842
|
+
for (const blockInputRaw of blocks.block) {
|
843
|
+
try {
|
844
|
+
// Parse properties and children if they are JSON strings
|
845
|
+
const properties = blockInputRaw.properties ? JSON.parse(blockInputRaw.properties) : {};
|
846
|
+
const children = blockInputRaw.children ? JSON.parse(blockInputRaw.children) : undefined;
|
847
|
+
const richText = blockInputRaw.richText ? parseRichTextInput(blockInputRaw.richText) : undefined;
|
848
|
+
|
849
|
+
// Create proper BlockInput structure
|
850
|
+
const blockInput: BlockInput = {
|
851
|
+
type: blockInputRaw.type,
|
852
|
+
content: blockInputRaw.content,
|
853
|
+
richText,
|
854
|
+
properties,
|
855
|
+
children,
|
856
|
+
};
|
857
|
+
|
858
|
+
const block = convertBlockInput(blockInput);
|
859
|
+
|
860
|
+
validateBlock(block);
|
861
|
+
blockData.push(block);
|
862
|
+
} catch (error) {
|
863
|
+
throw new NodeOperationError(
|
864
|
+
executeFunctions.getNode(),
|
865
|
+
`Error processing block: ${(error as Error).message}`,
|
866
|
+
);
|
867
|
+
}
|
868
|
+
}
|
869
|
+
|
870
|
+
return await notionApiRequest.call(executeFunctions, 'PATCH', `/blocks/${resolvedParentId}/children`, {
|
871
|
+
children: blockData,
|
872
|
+
});
|
873
|
+
}
|
874
|
+
|
875
|
+
private async getBlock(executeFunctions: IExecuteFunctions, itemIndex: number): Promise<IDataObject> {
|
876
|
+
const blockId = executeFunctions.getNodeParameter('blockId', itemIndex) as string;
|
877
|
+
|
878
|
+
return await notionApiRequest.call(executeFunctions, 'GET', `/blocks/${blockId}`);
|
879
|
+
}
|
880
|
+
|
881
|
+
private async updateBlock(executeFunctions: IExecuteFunctions, itemIndex: number): Promise<IDataObject> {
|
882
|
+
const blockId = executeFunctions.getNodeParameter('blockId', itemIndex) as string;
|
883
|
+
const blocks = executeFunctions.getNodeParameter('blocks', itemIndex, {}) as IDataObject;
|
884
|
+
|
885
|
+
if (!blocks.block || !Array.isArray(blocks.block) || blocks.block.length === 0) {
|
886
|
+
throw new NodeOperationError(executeFunctions.getNode(), 'No block data provided for update');
|
887
|
+
}
|
888
|
+
|
889
|
+
const blockInput = blocks.block[0];
|
890
|
+
const properties = blockInput.properties ? JSON.parse(blockInput.properties) : {};
|
891
|
+
const richText = blockInput.richText ? parseRichTextInput(blockInput.richText) : undefined;
|
892
|
+
|
893
|
+
const block = convertBlockInput({
|
894
|
+
type: blockInput.type,
|
895
|
+
content: blockInput.content,
|
896
|
+
richText,
|
897
|
+
properties,
|
898
|
+
});
|
899
|
+
|
900
|
+
validateBlock(block);
|
901
|
+
|
902
|
+
return await notionApiRequest.call(executeFunctions, 'PATCH', `/blocks/${blockId}`, block);
|
903
|
+
}
|
904
|
+
|
905
|
+
private async deleteBlock(executeFunctions: IExecuteFunctions, itemIndex: number): Promise<IDataObject> {
|
906
|
+
const blockId = executeFunctions.getNodeParameter('blockId', itemIndex) as string;
|
907
|
+
|
908
|
+
return await notionApiRequest.call(executeFunctions, 'DELETE', `/blocks/${blockId}`);
|
909
|
+
}
|
910
|
+
|
911
|
+
private async getBlockChildren(executeFunctions: IExecuteFunctions, itemIndex: number): Promise<IDataObject> {
|
912
|
+
const blockId = executeFunctions.getNodeParameter('blockId', itemIndex) as string;
|
913
|
+
|
914
|
+
const results: BlockWithId[] = await getBlocksWithIds.call(executeFunctions, blockId);
|
915
|
+
return { results, count: results.length };
|
916
|
+
}
|
917
|
+
|
918
|
+
private async appendBlockChildren(executeFunctions: IExecuteFunctions, itemIndex: number): Promise<IDataObject> {
|
919
|
+
const blockId = executeFunctions.getNodeParameter('blockId', itemIndex) as string;
|
920
|
+
const blocks = executeFunctions.getNodeParameter('blocks', itemIndex, {}) as IDataObject;
|
921
|
+
|
922
|
+
if (!blocks.block || !Array.isArray(blocks.block)) {
|
923
|
+
throw new NodeOperationError(executeFunctions.getNode(), 'No blocks provided');
|
924
|
+
}
|
925
|
+
|
926
|
+
const blockData: Block[] = [];
|
927
|
+
|
928
|
+
for (const blockInput of blocks.block) {
|
929
|
+
const properties = blockInput.properties ? JSON.parse(blockInput.properties) : {};
|
930
|
+
const children = blockInput.children ? JSON.parse(blockInput.children) : undefined;
|
931
|
+
const richText = blockInput.richText ? parseRichTextInput(blockInput.richText) : undefined;
|
932
|
+
|
933
|
+
const block = convertBlockInput({
|
934
|
+
type: blockInput.type,
|
935
|
+
content: blockInput.content,
|
936
|
+
richText,
|
937
|
+
properties,
|
938
|
+
children,
|
939
|
+
});
|
940
|
+
|
941
|
+
validateBlock(block);
|
942
|
+
blockData.push(block);
|
943
|
+
}
|
944
|
+
|
945
|
+
return await notionApiRequest.call(executeFunctions, 'PATCH', `/blocks/${blockId}/children`, {
|
946
|
+
children: blockData,
|
947
|
+
});
|
948
|
+
}
|
949
|
+
|
950
|
+
// DATABASE OPERATIONS
|
951
|
+
private async getDatabase(executeFunctions: IExecuteFunctions, itemIndex: number): Promise<IDataObject> {
|
952
|
+
const databaseId = executeFunctions.getNodeParameter('databaseId', itemIndex) as string;
|
953
|
+
|
954
|
+
return await notionApiRequest.call(executeFunctions, 'GET', `/databases/${databaseId}`);
|
955
|
+
}
|
956
|
+
|
957
|
+
private async queryDatabase(executeFunctions: IExecuteFunctions, itemIndex: number): Promise<IDataObject> {
|
958
|
+
const databaseId = executeFunctions.getNodeParameter('databaseId', itemIndex) as string;
|
959
|
+
const filter = executeFunctions.getNodeParameter('filter', itemIndex, '') as string;
|
960
|
+
|
961
|
+
const body: IDataObject = {};
|
962
|
+
|
963
|
+
if (filter) {
|
964
|
+
try {
|
965
|
+
body.filter = JSON.parse(filter);
|
966
|
+
} catch (error) {
|
967
|
+
throw new NodeOperationError(executeFunctions.getNode(), `Invalid filter JSON: ${(error as Error).message}`);
|
968
|
+
}
|
969
|
+
}
|
970
|
+
|
971
|
+
const results = await paginatedRequest.call(executeFunctions, 'POST', `/databases/${databaseId}/query`, body);
|
972
|
+
const response: NotionBlockChildrenResponse = {
|
973
|
+
object: 'list',
|
974
|
+
results,
|
975
|
+
count: results.length,
|
976
|
+
has_more: false,
|
977
|
+
next_cursor: null
|
978
|
+
};
|
979
|
+
return response;
|
980
|
+
}
|
981
|
+
|
982
|
+
private async createDatabase(executeFunctions: IExecuteFunctions, itemIndex: number): Promise<IDataObject> {
|
983
|
+
const parent = executeFunctions.getNodeParameter('parent', itemIndex) as string;
|
984
|
+
const title = executeFunctions.getNodeParameter('title', itemIndex) as string;
|
985
|
+
const properties = executeFunctions.getNodeParameter('properties', itemIndex, {}) as IDataObject;
|
986
|
+
|
987
|
+
const parentId = await resolvePageId.call(executeFunctions, parent);
|
988
|
+
|
989
|
+
const body: IDataObject = {
|
990
|
+
parent: { page_id: parentId },
|
991
|
+
title: [createRichText(title)],
|
992
|
+
properties: {},
|
993
|
+
};
|
994
|
+
|
995
|
+
// Add properties schema
|
996
|
+
if (properties.property && Array.isArray(properties.property)) {
|
997
|
+
for (const prop of properties.property) {
|
998
|
+
const { name, type, value } = prop;
|
999
|
+
try {
|
1000
|
+
const parsedValue = JSON.parse(value);
|
1001
|
+
body.properties[name] = { [type]: parsedValue };
|
1002
|
+
} catch {
|
1003
|
+
body.properties[name] = { [type]: {} };
|
1004
|
+
}
|
1005
|
+
}
|
1006
|
+
}
|
1007
|
+
|
1008
|
+
return await notionApiRequest.call(executeFunctions, 'POST', '/databases', body);
|
1009
|
+
}
|
1010
|
+
|
1011
|
+
// USER OPERATIONS
|
1012
|
+
private async getUser(executeFunctions: IExecuteFunctions, itemIndex: number): Promise<IDataObject> {
|
1013
|
+
const userId = executeFunctions.getNodeParameter('userId', itemIndex) as string;
|
1014
|
+
|
1015
|
+
return await notionApiRequest.call(executeFunctions, 'GET', `/users/${userId}`);
|
1016
|
+
}
|
1017
|
+
|
1018
|
+
private async listUsers(executeFunctions: IExecuteFunctions, _itemIndex: number): Promise<IDataObject> {
|
1019
|
+
const results = await paginatedRequest.call(executeFunctions, 'GET', '/users');
|
1020
|
+
return { results, count: results.length };
|
1021
|
+
}
|
1022
|
+
}
|