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.
@@ -0,0 +1,104 @@
1
+ import { IDataObject, IExecuteFunctions, IHttpRequestMethods, INodeExecutionData } from 'n8n-workflow';
2
+ import { Block, BlockInput, BlockWithId, RichTextObject, RichTextAnnotations, NotionColor, PageInput } from '../../types/NotionTypes';
3
+ /**
4
+ * Makes an authenticated request to the Notion API
5
+ */
6
+ export declare function notionApiRequest(this: IExecuteFunctions, method: IHttpRequestMethods, endpoint: string, body?: IDataObject, qs?: IDataObject): Promise<any>;
7
+ /**
8
+ * Validates Notion API credentials by making a test request
9
+ */
10
+ export declare function validateCredentials(this: IExecuteFunctions): Promise<boolean>;
11
+ /**
12
+ * Creates a rich text object from a string with optional formatting
13
+ */
14
+ export declare function createRichText(text: string, annotations?: Partial<RichTextAnnotations>, link?: string): RichTextObject;
15
+ /**
16
+ * Parses rich text input from various formats
17
+ */
18
+ export declare function parseRichTextInput(input: any): RichTextObject[];
19
+ /**
20
+ * Creates a paragraph block
21
+ */
22
+ export declare function createParagraphBlock(text: string | RichTextObject[], color?: NotionColor, children?: Block[]): Block;
23
+ /**
24
+ * Creates a heading block
25
+ */
26
+ export declare function createHeadingBlock(level: 1 | 2 | 3, text: string | RichTextObject[], color?: NotionColor, isToggleable?: boolean): Block;
27
+ /**
28
+ * Creates a list item block
29
+ */
30
+ export declare function createListItemBlock(type: 'bulleted_list_item' | 'numbered_list_item', text: string | RichTextObject[], color?: NotionColor, children?: Block[]): Block;
31
+ /**
32
+ * Creates a to-do block
33
+ */
34
+ export declare function createToDoBlock(text: string | RichTextObject[], checked?: boolean, color?: NotionColor, children?: Block[]): Block;
35
+ /**
36
+ * Creates a code block
37
+ */
38
+ export declare function createCodeBlock(code: string, language?: string, caption?: RichTextObject[]): Block;
39
+ /**
40
+ * Creates a quote block
41
+ */
42
+ export declare function createQuoteBlock(text: string | RichTextObject[], color?: NotionColor, children?: Block[]): Block;
43
+ /**
44
+ * Creates a callout block
45
+ */
46
+ export declare function createCalloutBlock(text: string | RichTextObject[], icon?: string, color?: NotionColor, children?: Block[]): Block;
47
+ /**
48
+ * Creates a divider block
49
+ */
50
+ export declare function createDividerBlock(): Block;
51
+ /**
52
+ * Creates an equation block
53
+ */
54
+ export declare function createEquationBlock(expression: string): Block;
55
+ /**
56
+ * Creates an image block
57
+ */
58
+ export declare function createImageBlock(url: string, caption?: RichTextObject[]): Block;
59
+ /**
60
+ * Creates a bookmark block
61
+ */
62
+ export declare function createBookmarkBlock(url: string, caption?: RichTextObject[]): Block;
63
+ /**
64
+ * Creates an embed block
65
+ */
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;
71
+ /**
72
+ * Creates a table block with rows
73
+ */
74
+ export declare function createTableBlock(tableWidth: number, rows: RichTextObject[][][], hasColumnHeader?: boolean, hasRowHeader?: boolean): Block;
75
+ /**
76
+ * Converts BlockInput to actual Block objects
77
+ */
78
+ export declare function convertBlockInput(blockInput: BlockInput): Block;
79
+ /**
80
+ * Resolves a page ID from various input formats (URL, ID, title search)
81
+ */
82
+ export declare function resolvePageId(this: IExecuteFunctions, pageInput: string): Promise<string>;
83
+ /**
84
+ * Validates a block structure before sending to Notion API
85
+ */
86
+ export declare function validateBlock(block: Block): void;
87
+ /**
88
+ * Paginated request helper for Notion API
89
+ */
90
+ export declare function paginatedRequest(this: IExecuteFunctions, method: IHttpRequestMethods, endpoint: string, body?: IDataObject): Promise<any[]>;
91
+ /**
92
+ * Creates page input from parameters for validation
93
+ */
94
+ export declare function createPageInput(title: string, parent: string, properties?: {
95
+ [key: string]: any;
96
+ }, children?: BlockInput[], icon?: string, cover?: string): PageInput;
97
+ /**
98
+ * Gets blocks with full metadata including IDs
99
+ */
100
+ export declare function getBlocksWithIds(this: IExecuteFunctions, blockId: string): Promise<BlockWithId[]>;
101
+ /**
102
+ * Creates execution data from results
103
+ */
104
+ export declare function createExecutionData(data: IDataObject[]): INodeExecutionData[];
@@ -0,0 +1,465 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.notionApiRequest = notionApiRequest;
4
+ exports.validateCredentials = validateCredentials;
5
+ exports.createRichText = createRichText;
6
+ exports.parseRichTextInput = parseRichTextInput;
7
+ exports.createParagraphBlock = createParagraphBlock;
8
+ exports.createHeadingBlock = createHeadingBlock;
9
+ exports.createListItemBlock = createListItemBlock;
10
+ exports.createToDoBlock = createToDoBlock;
11
+ exports.createCodeBlock = createCodeBlock;
12
+ exports.createQuoteBlock = createQuoteBlock;
13
+ exports.createCalloutBlock = createCalloutBlock;
14
+ exports.createDividerBlock = createDividerBlock;
15
+ exports.createEquationBlock = createEquationBlock;
16
+ exports.createImageBlock = createImageBlock;
17
+ exports.createBookmarkBlock = createBookmarkBlock;
18
+ exports.createEmbedBlock = createEmbedBlock;
19
+ exports.createToggleBlock = createToggleBlock;
20
+ exports.createTableBlock = createTableBlock;
21
+ exports.convertBlockInput = convertBlockInput;
22
+ exports.resolvePageId = resolvePageId;
23
+ exports.validateBlock = validateBlock;
24
+ exports.paginatedRequest = paginatedRequest;
25
+ exports.createPageInput = createPageInput;
26
+ exports.getBlocksWithIds = getBlocksWithIds;
27
+ exports.createExecutionData = createExecutionData;
28
+ const n8n_workflow_1 = require("n8n-workflow");
29
+ /**
30
+ * Makes an authenticated request to the Notion API
31
+ */
32
+ async function notionApiRequest(method, endpoint, body = {}, qs = {}) {
33
+ const credentials = (await this.getCredentials('notionApi'));
34
+ const options = {
35
+ method,
36
+ headers: {
37
+ 'Authorization': `Bearer ${credentials.apiKey}`,
38
+ 'Notion-Version': '2022-06-28',
39
+ 'Content-Type': 'application/json',
40
+ },
41
+ url: `https://api.notion.com/v1${endpoint}`,
42
+ body,
43
+ qs,
44
+ json: true,
45
+ };
46
+ try {
47
+ return await this.helpers.httpRequest(options);
48
+ }
49
+ catch (error) {
50
+ throw new n8n_workflow_1.NodeApiError(this.getNode(), {
51
+ message: error.message,
52
+ description: 'Failed to make Notion API request',
53
+ httpCode: error.status || error.statusCode || 500,
54
+ });
55
+ }
56
+ }
57
+ /**
58
+ * Validates Notion API credentials by making a test request
59
+ */
60
+ async function validateCredentials() {
61
+ try {
62
+ await notionApiRequest.call(this, 'GET', '/users/me');
63
+ return true;
64
+ }
65
+ catch (error) {
66
+ return false;
67
+ }
68
+ }
69
+ /**
70
+ * Creates a rich text object from a string with optional formatting
71
+ */
72
+ function createRichText(text, annotations = {}, link) {
73
+ return {
74
+ type: 'text',
75
+ text: {
76
+ content: text,
77
+ link: link ? { url: link } : null,
78
+ },
79
+ annotations: {
80
+ bold: annotations.bold || false,
81
+ italic: annotations.italic || false,
82
+ strikethrough: annotations.strikethrough || false,
83
+ underline: annotations.underline || false,
84
+ code: annotations.code || false,
85
+ color: annotations.color || 'default',
86
+ },
87
+ plain_text: text,
88
+ href: link || null,
89
+ };
90
+ }
91
+ /**
92
+ * Parses rich text input from various formats
93
+ */
94
+ function parseRichTextInput(input) {
95
+ if (typeof input === 'string') {
96
+ return [createRichText(input)];
97
+ }
98
+ if (Array.isArray(input)) {
99
+ return input.map((item) => {
100
+ if (typeof item === 'string') {
101
+ return createRichText(item);
102
+ }
103
+ if (typeof item === 'object' && item !== null) {
104
+ return createRichText(item.text || item.content || '', item.annotations || {}, item.link || item.url);
105
+ }
106
+ return createRichText('');
107
+ });
108
+ }
109
+ if (typeof input === 'object' && input !== null) {
110
+ if (input.type === 'text' || input.type === 'mention' || input.type === 'equation') {
111
+ return [input];
112
+ }
113
+ return [createRichText(input.text || input.content || '', input.annotations || {}, input.link || input.url)];
114
+ }
115
+ return [createRichText('')];
116
+ }
117
+ /**
118
+ * Creates a paragraph block
119
+ */
120
+ function createParagraphBlock(text, color, children) {
121
+ return {
122
+ type: 'paragraph',
123
+ paragraph: {
124
+ rich_text: typeof text === 'string' ? [createRichText(text)] : text,
125
+ color,
126
+ children,
127
+ },
128
+ };
129
+ }
130
+ /**
131
+ * Creates a heading block
132
+ */
133
+ function createHeadingBlock(level, text, color, isToggleable) {
134
+ const richText = typeof text === 'string' ? [createRichText(text)] : text;
135
+ const headingData = {
136
+ rich_text: richText,
137
+ color,
138
+ is_toggleable: isToggleable,
139
+ };
140
+ switch (level) {
141
+ case 1:
142
+ return {
143
+ type: 'heading_1',
144
+ heading_1: headingData,
145
+ };
146
+ case 2:
147
+ return {
148
+ type: 'heading_2',
149
+ heading_2: headingData,
150
+ };
151
+ case 3:
152
+ return {
153
+ type: 'heading_3',
154
+ heading_3: headingData,
155
+ };
156
+ default:
157
+ throw new Error('Invalid heading level. Must be 1, 2, or 3.');
158
+ }
159
+ }
160
+ /**
161
+ * Creates a list item block
162
+ */
163
+ function createListItemBlock(type, text, color, children) {
164
+ const richText = typeof text === 'string' ? [createRichText(text)] : text;
165
+ if (type === 'bulleted_list_item') {
166
+ return {
167
+ type: 'bulleted_list_item',
168
+ bulleted_list_item: {
169
+ rich_text: richText,
170
+ color,
171
+ children,
172
+ },
173
+ };
174
+ }
175
+ else {
176
+ return {
177
+ type: 'numbered_list_item',
178
+ numbered_list_item: {
179
+ rich_text: richText,
180
+ color,
181
+ children,
182
+ },
183
+ };
184
+ }
185
+ }
186
+ /**
187
+ * Creates a to-do block
188
+ */
189
+ function createToDoBlock(text, checked = false, color, children) {
190
+ return {
191
+ type: 'to_do',
192
+ to_do: {
193
+ rich_text: typeof text === 'string' ? [createRichText(text)] : text,
194
+ checked,
195
+ color,
196
+ children,
197
+ },
198
+ };
199
+ }
200
+ /**
201
+ * Creates a code block
202
+ */
203
+ function createCodeBlock(code, language, caption) {
204
+ return {
205
+ type: 'code',
206
+ code: {
207
+ rich_text: [createRichText(code)],
208
+ language,
209
+ caption,
210
+ },
211
+ };
212
+ }
213
+ /**
214
+ * Creates a quote block
215
+ */
216
+ function createQuoteBlock(text, color, children) {
217
+ return {
218
+ type: 'quote',
219
+ quote: {
220
+ rich_text: typeof text === 'string' ? [createRichText(text)] : text,
221
+ color,
222
+ children,
223
+ },
224
+ };
225
+ }
226
+ /**
227
+ * Creates a callout block
228
+ */
229
+ function createCalloutBlock(text, icon, color, children) {
230
+ const iconObject = icon ? { type: 'emoji', emoji: icon } : undefined;
231
+ return {
232
+ type: 'callout',
233
+ callout: {
234
+ rich_text: typeof text === 'string' ? [createRichText(text)] : text,
235
+ icon: iconObject,
236
+ color,
237
+ children,
238
+ },
239
+ };
240
+ }
241
+ /**
242
+ * Creates a divider block
243
+ */
244
+ function createDividerBlock() {
245
+ return {
246
+ type: 'divider',
247
+ divider: {},
248
+ };
249
+ }
250
+ /**
251
+ * Creates an equation block
252
+ */
253
+ function createEquationBlock(expression) {
254
+ return {
255
+ type: 'equation',
256
+ equation: {
257
+ expression,
258
+ },
259
+ };
260
+ }
261
+ /**
262
+ * Creates an image block
263
+ */
264
+ function createImageBlock(url, caption) {
265
+ return {
266
+ type: 'image',
267
+ image: {
268
+ type: 'external',
269
+ external: { url },
270
+ caption,
271
+ },
272
+ };
273
+ }
274
+ /**
275
+ * Creates a bookmark block
276
+ */
277
+ function createBookmarkBlock(url, caption) {
278
+ return {
279
+ type: 'bookmark',
280
+ bookmark: {
281
+ url,
282
+ caption,
283
+ },
284
+ };
285
+ }
286
+ /**
287
+ * Creates an embed block
288
+ */
289
+ function createEmbedBlock(url, caption) {
290
+ return {
291
+ type: 'embed',
292
+ embed: {
293
+ url,
294
+ caption,
295
+ },
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
+ }
311
+ /**
312
+ * Creates a table block with rows
313
+ */
314
+ function createTableBlock(tableWidth, rows, hasColumnHeader = false, hasRowHeader = false) {
315
+ const tableRows = rows.map(cells => ({
316
+ type: 'table_row',
317
+ table_row: { cells },
318
+ }));
319
+ return {
320
+ type: 'table',
321
+ table: {
322
+ table_width: tableWidth,
323
+ has_column_header: hasColumnHeader,
324
+ has_row_header: hasRowHeader,
325
+ children: tableRows,
326
+ },
327
+ };
328
+ }
329
+ /**
330
+ * Converts BlockInput to actual Block objects
331
+ */
332
+ function convertBlockInput(blockInput) {
333
+ const { type, content = '', properties = {}, children } = blockInput;
334
+ const richText = parseRichTextInput(blockInput.richText || content);
335
+ const childBlocks = children ? children.map(convertBlockInput) : undefined;
336
+ switch (type) {
337
+ case 'paragraph':
338
+ return createParagraphBlock(richText, properties.color, childBlocks);
339
+ case 'heading_1':
340
+ case 'heading_2':
341
+ case 'heading_3':
342
+ const level = parseInt(type.split('_')[1]);
343
+ return createHeadingBlock(level, richText, properties.color, properties.isToggleable);
344
+ case 'bulleted_list_item':
345
+ case 'numbered_list_item':
346
+ return createListItemBlock(type, richText, properties.color, childBlocks);
347
+ case 'to_do':
348
+ return createToDoBlock(richText, properties.checked, properties.color, childBlocks);
349
+ case 'code':
350
+ return createCodeBlock(content, properties.language, properties.caption);
351
+ case 'quote':
352
+ return createQuoteBlock(richText, properties.color, childBlocks);
353
+ case 'callout':
354
+ return createCalloutBlock(richText, properties.icon, properties.color, childBlocks);
355
+ case 'divider':
356
+ return createDividerBlock();
357
+ case 'equation':
358
+ return createEquationBlock(properties.expression || content);
359
+ case 'image':
360
+ return createImageBlock(properties.url || content, properties.caption);
361
+ case 'bookmark':
362
+ return createBookmarkBlock(properties.url || content, properties.caption);
363
+ case 'embed':
364
+ return createEmbedBlock(properties.url || content, properties.caption);
365
+ default:
366
+ throw new Error(`Unsupported block type: ${type}`);
367
+ }
368
+ }
369
+ /**
370
+ * Resolves a page ID from various input formats (URL, ID, title search)
371
+ */
372
+ async function resolvePageId(pageInput) {
373
+ // If it looks like a UUID, return it directly
374
+ const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
375
+ if (uuidRegex.test(pageInput)) {
376
+ return pageInput;
377
+ }
378
+ // If it looks like a Notion URL, extract the ID
379
+ const urlRegex = /https:\/\/www\.notion\.so\/[^\/]*-([a-f0-9]{32})/;
380
+ const urlMatch = pageInput.match(urlRegex);
381
+ if (urlMatch) {
382
+ const rawId = urlMatch[1];
383
+ // Convert 32-character ID to UUID format
384
+ return `${rawId.slice(0, 8)}-${rawId.slice(8, 12)}-${rawId.slice(12, 16)}-${rawId.slice(16, 20)}-${rawId.slice(20)}`;
385
+ }
386
+ // Otherwise, search for page by title
387
+ const searchResponse = await notionApiRequest.call(this, 'POST', '/search', {
388
+ query: pageInput,
389
+ filter: { property: 'object', value: 'page' },
390
+ });
391
+ if (searchResponse.results && searchResponse.results.length > 0) {
392
+ const page = searchResponse.results[0];
393
+ return page.id;
394
+ }
395
+ throw new n8n_workflow_1.NodeOperationError(this.getNode(), `Could not find page with identifier: ${pageInput}`);
396
+ }
397
+ /**
398
+ * Validates a block structure before sending to Notion API
399
+ */
400
+ function validateBlock(block) {
401
+ if (!block.type) {
402
+ throw new Error('Block must have a type property');
403
+ }
404
+ // Add specific validation for each block type as needed
405
+ switch (block.type) {
406
+ case 'paragraph':
407
+ if (!('paragraph' in block) || !block.paragraph || !Array.isArray(block.paragraph.rich_text)) {
408
+ throw new Error('Paragraph block must have rich_text array');
409
+ }
410
+ break;
411
+ case 'code':
412
+ if (!('code' in block) || !block.code || !Array.isArray(block.code.rich_text)) {
413
+ throw new Error('Code block must have rich_text array');
414
+ }
415
+ break;
416
+ // Add more validation cases as needed
417
+ }
418
+ }
419
+ /**
420
+ * Paginated request helper for Notion API
421
+ */
422
+ async function paginatedRequest(method, endpoint, body = {}) {
423
+ const results = [];
424
+ let hasMore = true;
425
+ let nextCursor;
426
+ while (hasMore) {
427
+ const requestBody = { ...body };
428
+ if (nextCursor) {
429
+ requestBody.start_cursor = nextCursor;
430
+ }
431
+ const response = await notionApiRequest.call(this, method, endpoint, requestBody);
432
+ if (response.results) {
433
+ results.push(...response.results);
434
+ }
435
+ hasMore = response.has_more || false;
436
+ nextCursor = response.next_cursor || undefined;
437
+ }
438
+ return results;
439
+ }
440
+ /**
441
+ * Creates page input from parameters for validation
442
+ */
443
+ function createPageInput(title, parent, properties, children, icon, cover) {
444
+ return {
445
+ title,
446
+ parent,
447
+ properties,
448
+ children,
449
+ icon,
450
+ cover,
451
+ };
452
+ }
453
+ /**
454
+ * Gets blocks with full metadata including IDs
455
+ */
456
+ async function getBlocksWithIds(blockId) {
457
+ const response = await notionApiRequest.call(this, 'GET', `/blocks/${blockId}/children`);
458
+ return response.results;
459
+ }
460
+ /**
461
+ * Creates execution data from results
462
+ */
463
+ function createExecutionData(data) {
464
+ return data.map(item => ({ json: item }));
465
+ }