@pagecrawl/n8n-nodes-pagecrawl 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +227 -0
- package/dist/credentials/PageCrawlApi.credentials.d.ts +9 -0
- package/dist/credentials/PageCrawlApi.credentials.js +57 -0
- package/dist/icons/pagecrawl.svg +24 -0
- package/dist/nodes/PageCrawl/PageCrawl.node.d.ts +5 -0
- package/dist/nodes/PageCrawl/PageCrawl.node.js +467 -0
- package/dist/nodes/PageCrawl/PageCrawl.node.json +22 -0
- package/dist/nodes/PageCrawl/descriptions/CheckDescription.d.ts +3 -0
- package/dist/nodes/PageCrawl/descriptions/CheckDescription.js +110 -0
- package/dist/nodes/PageCrawl/descriptions/PageDescription.d.ts +3 -0
- package/dist/nodes/PageCrawl/descriptions/PageDescription.js +657 -0
- package/dist/nodes/PageCrawl/descriptions/ScreenshotDescription.d.ts +3 -0
- package/dist/nodes/PageCrawl/descriptions/ScreenshotDescription.js +78 -0
- package/dist/nodes/PageCrawl/descriptions/WebhookDescription.d.ts +3 -0
- package/dist/nodes/PageCrawl/descriptions/WebhookDescription.js +203 -0
- package/dist/nodes/PageCrawl/pagecrawl.svg +18 -0
- package/dist/nodes/PageCrawl/types.d.ts +98 -0
- package/dist/nodes/PageCrawl/types.js +53 -0
- package/dist/nodes/PageCrawlTrigger/PageCrawlTrigger.node.d.ts +12 -0
- package/dist/nodes/PageCrawlTrigger/PageCrawlTrigger.node.js +221 -0
- package/dist/nodes/PageCrawlTrigger/PageCrawlTrigger.node.json +22 -0
- package/dist/nodes/PageCrawlTrigger/pagecrawl.svg +18 -0
- package/package.json +64 -0
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.screenshotFields = exports.screenshotOperations = void 0;
|
|
4
|
+
exports.screenshotOperations = [
|
|
5
|
+
{
|
|
6
|
+
displayName: 'Operation',
|
|
7
|
+
name: 'operation',
|
|
8
|
+
type: 'options',
|
|
9
|
+
noDataExpression: true,
|
|
10
|
+
displayOptions: {
|
|
11
|
+
show: {
|
|
12
|
+
resource: ['screenshot'],
|
|
13
|
+
},
|
|
14
|
+
},
|
|
15
|
+
options: [
|
|
16
|
+
{
|
|
17
|
+
name: 'Get Check Screenshot',
|
|
18
|
+
value: 'getCheckScreenshot',
|
|
19
|
+
description: 'Get screenshot for a specific check',
|
|
20
|
+
action: 'Get check screenshot',
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
name: 'Get Check Screenshot Diff',
|
|
24
|
+
value: 'getCheckDiff',
|
|
25
|
+
description: 'Get screenshot diff for a specific check',
|
|
26
|
+
action: 'Get check screenshot diff',
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
name: 'Get Latest Screenshot',
|
|
30
|
+
value: 'getLatest',
|
|
31
|
+
description: 'Get latest full-page screenshot',
|
|
32
|
+
action: 'Get latest screenshot',
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
name: 'Get Latest Screenshot Diff',
|
|
36
|
+
value: 'getLatestDiff',
|
|
37
|
+
description: 'Get latest screenshot diff',
|
|
38
|
+
action: 'Get latest screenshot diff',
|
|
39
|
+
},
|
|
40
|
+
],
|
|
41
|
+
default: 'getLatest',
|
|
42
|
+
},
|
|
43
|
+
];
|
|
44
|
+
exports.screenshotFields = [
|
|
45
|
+
// ========================================
|
|
46
|
+
// screenshot:all
|
|
47
|
+
// ========================================
|
|
48
|
+
{
|
|
49
|
+
displayName: 'Page ID',
|
|
50
|
+
name: 'pageId',
|
|
51
|
+
type: 'string',
|
|
52
|
+
required: true,
|
|
53
|
+
displayOptions: {
|
|
54
|
+
show: {
|
|
55
|
+
resource: ['screenshot'],
|
|
56
|
+
},
|
|
57
|
+
},
|
|
58
|
+
default: '',
|
|
59
|
+
description: 'The ID or slug of the page',
|
|
60
|
+
},
|
|
61
|
+
// ========================================
|
|
62
|
+
// screenshot:getCheckScreenshot, getCheckDiff
|
|
63
|
+
// ========================================
|
|
64
|
+
{
|
|
65
|
+
displayName: 'Check ID',
|
|
66
|
+
name: 'checkId',
|
|
67
|
+
type: 'string',
|
|
68
|
+
required: true,
|
|
69
|
+
displayOptions: {
|
|
70
|
+
show: {
|
|
71
|
+
resource: ['screenshot'],
|
|
72
|
+
operation: ['getCheckScreenshot', 'getCheckDiff'],
|
|
73
|
+
},
|
|
74
|
+
},
|
|
75
|
+
default: '',
|
|
76
|
+
description: 'The check ID (use "latest" for most recent)',
|
|
77
|
+
},
|
|
78
|
+
];
|
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.webhookFields = exports.webhookOperations = void 0;
|
|
4
|
+
const types_1 = require("../types");
|
|
5
|
+
exports.webhookOperations = [
|
|
6
|
+
{
|
|
7
|
+
displayName: 'Operation',
|
|
8
|
+
name: 'operation',
|
|
9
|
+
type: 'options',
|
|
10
|
+
noDataExpression: true,
|
|
11
|
+
displayOptions: {
|
|
12
|
+
show: {
|
|
13
|
+
resource: ['webhook'],
|
|
14
|
+
},
|
|
15
|
+
},
|
|
16
|
+
options: [
|
|
17
|
+
{
|
|
18
|
+
name: 'Create',
|
|
19
|
+
value: 'create',
|
|
20
|
+
description: 'Create a new webhook',
|
|
21
|
+
action: 'Create a webhook',
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
name: 'Delete',
|
|
25
|
+
value: 'delete',
|
|
26
|
+
description: 'Delete a webhook',
|
|
27
|
+
action: 'Delete a webhook',
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
name: 'Get Many',
|
|
31
|
+
value: 'getAll',
|
|
32
|
+
description: 'Get all webhooks',
|
|
33
|
+
action: 'Get many webhooks',
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
name: 'Test',
|
|
37
|
+
value: 'test',
|
|
38
|
+
description: 'Test a webhook',
|
|
39
|
+
action: 'Test a webhook',
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
name: 'Update',
|
|
43
|
+
value: 'update',
|
|
44
|
+
description: 'Update a webhook',
|
|
45
|
+
action: 'Update a webhook',
|
|
46
|
+
},
|
|
47
|
+
],
|
|
48
|
+
default: 'getAll',
|
|
49
|
+
},
|
|
50
|
+
];
|
|
51
|
+
exports.webhookFields = [
|
|
52
|
+
// ========================================
|
|
53
|
+
// webhook:getAll
|
|
54
|
+
// ========================================
|
|
55
|
+
{
|
|
56
|
+
displayName: 'Return All',
|
|
57
|
+
name: 'returnAll',
|
|
58
|
+
type: 'boolean',
|
|
59
|
+
displayOptions: {
|
|
60
|
+
show: {
|
|
61
|
+
resource: ['webhook'],
|
|
62
|
+
operation: ['getAll'],
|
|
63
|
+
},
|
|
64
|
+
},
|
|
65
|
+
default: true,
|
|
66
|
+
description: 'Whether to return all results or only up to a given limit',
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
displayName: 'Limit',
|
|
70
|
+
name: 'limit',
|
|
71
|
+
type: 'number',
|
|
72
|
+
displayOptions: {
|
|
73
|
+
show: {
|
|
74
|
+
resource: ['webhook'],
|
|
75
|
+
operation: ['getAll'],
|
|
76
|
+
returnAll: [false],
|
|
77
|
+
},
|
|
78
|
+
},
|
|
79
|
+
typeOptions: {
|
|
80
|
+
minValue: 1,
|
|
81
|
+
},
|
|
82
|
+
default: 50,
|
|
83
|
+
description: 'Max number of results to return',
|
|
84
|
+
},
|
|
85
|
+
// ========================================
|
|
86
|
+
// webhook:create
|
|
87
|
+
// ========================================
|
|
88
|
+
{
|
|
89
|
+
displayName: 'Target URL',
|
|
90
|
+
name: 'target_url',
|
|
91
|
+
type: 'string',
|
|
92
|
+
required: true,
|
|
93
|
+
displayOptions: {
|
|
94
|
+
show: {
|
|
95
|
+
resource: ['webhook'],
|
|
96
|
+
operation: ['create'],
|
|
97
|
+
},
|
|
98
|
+
},
|
|
99
|
+
default: '',
|
|
100
|
+
placeholder: 'https://example.com/webhook',
|
|
101
|
+
description: 'The URL where webhook data will be sent',
|
|
102
|
+
},
|
|
103
|
+
{
|
|
104
|
+
displayName: 'Additional Fields',
|
|
105
|
+
name: 'additionalFields',
|
|
106
|
+
type: 'collection',
|
|
107
|
+
placeholder: 'Add Field',
|
|
108
|
+
default: {},
|
|
109
|
+
displayOptions: {
|
|
110
|
+
show: {
|
|
111
|
+
resource: ['webhook'],
|
|
112
|
+
operation: ['create'],
|
|
113
|
+
},
|
|
114
|
+
},
|
|
115
|
+
options: [
|
|
116
|
+
{
|
|
117
|
+
displayName: 'Page ID',
|
|
118
|
+
name: 'change_id',
|
|
119
|
+
type: 'string',
|
|
120
|
+
default: '',
|
|
121
|
+
description: 'Specific page ID to track (leave empty for all pages)',
|
|
122
|
+
},
|
|
123
|
+
{
|
|
124
|
+
displayName: 'Payload Fields',
|
|
125
|
+
name: 'payload_fields',
|
|
126
|
+
type: 'multiOptions',
|
|
127
|
+
options: types_1.WEBHOOK_PAYLOAD_FIELDS.map((field) => ({
|
|
128
|
+
name: field.replace(/_/g, ' ').replace(/\b\w/g, (l) => l.toUpperCase()),
|
|
129
|
+
value: field,
|
|
130
|
+
})),
|
|
131
|
+
default: [],
|
|
132
|
+
description: 'Fields to include in webhook payload (all if empty)',
|
|
133
|
+
},
|
|
134
|
+
],
|
|
135
|
+
},
|
|
136
|
+
// ========================================
|
|
137
|
+
// webhook:update, delete, test
|
|
138
|
+
// ========================================
|
|
139
|
+
{
|
|
140
|
+
displayName: 'Webhook ID',
|
|
141
|
+
name: 'webhookId',
|
|
142
|
+
type: 'string',
|
|
143
|
+
required: true,
|
|
144
|
+
displayOptions: {
|
|
145
|
+
show: {
|
|
146
|
+
resource: ['webhook'],
|
|
147
|
+
operation: ['update', 'delete', 'test'],
|
|
148
|
+
},
|
|
149
|
+
},
|
|
150
|
+
default: '',
|
|
151
|
+
description: 'The ID of the webhook',
|
|
152
|
+
},
|
|
153
|
+
// ========================================
|
|
154
|
+
// webhook:update
|
|
155
|
+
// ========================================
|
|
156
|
+
{
|
|
157
|
+
displayName: 'Update Fields',
|
|
158
|
+
name: 'updateFields',
|
|
159
|
+
type: 'collection',
|
|
160
|
+
placeholder: 'Add Field',
|
|
161
|
+
default: {},
|
|
162
|
+
displayOptions: {
|
|
163
|
+
show: {
|
|
164
|
+
resource: ['webhook'],
|
|
165
|
+
operation: ['update'],
|
|
166
|
+
},
|
|
167
|
+
},
|
|
168
|
+
options: [
|
|
169
|
+
{
|
|
170
|
+
displayName: 'Active',
|
|
171
|
+
name: 'is_active',
|
|
172
|
+
type: 'boolean',
|
|
173
|
+
default: true,
|
|
174
|
+
description: 'Whether the webhook is active',
|
|
175
|
+
},
|
|
176
|
+
{
|
|
177
|
+
displayName: 'Page ID',
|
|
178
|
+
name: 'change_id',
|
|
179
|
+
type: 'string',
|
|
180
|
+
default: '',
|
|
181
|
+
description: 'Specific page ID to track',
|
|
182
|
+
},
|
|
183
|
+
{
|
|
184
|
+
displayName: 'Payload Fields',
|
|
185
|
+
name: 'payload_fields',
|
|
186
|
+
type: 'multiOptions',
|
|
187
|
+
options: types_1.WEBHOOK_PAYLOAD_FIELDS.map((field) => ({
|
|
188
|
+
name: field.replace(/_/g, ' ').replace(/\b\w/g, (l) => l.toUpperCase()),
|
|
189
|
+
value: field,
|
|
190
|
+
})),
|
|
191
|
+
default: [],
|
|
192
|
+
description: 'Fields to include in webhook payload',
|
|
193
|
+
},
|
|
194
|
+
{
|
|
195
|
+
displayName: 'Target URL',
|
|
196
|
+
name: 'target_url',
|
|
197
|
+
type: 'string',
|
|
198
|
+
default: '',
|
|
199
|
+
description: 'The URL where webhook data will be sent',
|
|
200
|
+
},
|
|
201
|
+
],
|
|
202
|
+
},
|
|
203
|
+
];
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64" width="64" height="64">
|
|
2
|
+
<!-- Background circle with outline -->
|
|
3
|
+
<circle cx="32" cy="32" r="28" fill="#2955c3" stroke="#1e3d8f" stroke-width="2"/>
|
|
4
|
+
|
|
5
|
+
<!-- PageCrawl logo paths (centered with more padding) -->
|
|
6
|
+
<g transform="translate(32, 32) scale(0.015, -0.015) translate(-1400, -1400)" fill="white" stroke="none">
|
|
7
|
+
<path d="M1290 2574 c-553 -67 -1049 -128 -1102 -134 -54 -7 -99 -17 -101 -24
|
|
8
|
+
-3 -6 8 -115 24 -241 16 -127 29 -236 29 -242 0 -14 28 -17 47 -5 9 5 5 59
|
|
9
|
+
-14 220 -15 117 -23 215 -19 219 6 6 2049 262 2096 263 13 0 20 -35 39 -192
|
|
10
|
+
31 -257 29 -248 57 -248 20 0 24 5 24 30 0 69 -53 456 -63 466 -9 8 -278 -21
|
|
11
|
+
-1017 -112z"/>
|
|
12
|
+
<path d="M2568 943 c-12 -3 -15 -12 -12 -36 25 -163 49 -409 40 -412 -29 -10
|
|
13
|
+
-2087 -257 -2099 -252 -9 3 -20 66 -36 203 -12 110 -25 207 -27 217 -3 10 -15
|
|
14
|
+
17 -30 17 -18 0 -24 -5 -24 -22 -1 -59 54 -464 64 -475 9 -9 257 18 1105 122
|
|
15
|
+
601 74 1097 135 1101 135 4 0 10 7 14 15 6 16 -49 469 -59 485 -6 10 -9 11
|
|
16
|
+
-37 3z"/>
|
|
17
|
+
</g>
|
|
18
|
+
</svg>
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
export interface IPageElement {
|
|
2
|
+
type: 'text' | 'number' | 'fullpage';
|
|
3
|
+
selector: string;
|
|
4
|
+
label: string;
|
|
5
|
+
}
|
|
6
|
+
export interface INotificationRule {
|
|
7
|
+
type: 'text_difference' | 'added' | 'removed' | 'contains' | 'ncontains' | 'eq' | 'neq' | 'increased' | 'decreased' | 'is' | 'gt' | 'lt' | 'gte' | 'lte';
|
|
8
|
+
value: string | number;
|
|
9
|
+
element?: number;
|
|
10
|
+
}
|
|
11
|
+
export interface IPageAction {
|
|
12
|
+
type: 'scroll_to_bottom' | 'remove_dates' | 'remove_cookies' | 'remove_cookies_v2' | 'click' | 'hover' | 'type' | 'select' | 'remove_element' | 'wait_element' | 'wait' | 'javascript' | 'back';
|
|
13
|
+
selector?: string;
|
|
14
|
+
value?: string | number;
|
|
15
|
+
}
|
|
16
|
+
export interface IPage {
|
|
17
|
+
id: number;
|
|
18
|
+
name: string;
|
|
19
|
+
slug: string;
|
|
20
|
+
url: string;
|
|
21
|
+
url_tld: string;
|
|
22
|
+
created_at: string | null;
|
|
23
|
+
last_checked_at: string | null;
|
|
24
|
+
status: string;
|
|
25
|
+
failed: number;
|
|
26
|
+
disabled?: boolean;
|
|
27
|
+
frequency?: number;
|
|
28
|
+
location?: string;
|
|
29
|
+
folder_id?: number;
|
|
30
|
+
template_id?: number;
|
|
31
|
+
auth_id?: number;
|
|
32
|
+
skip_first_notification?: boolean;
|
|
33
|
+
notifications?: string[];
|
|
34
|
+
notification_emails?: string;
|
|
35
|
+
fail_silently?: number;
|
|
36
|
+
check_always?: boolean;
|
|
37
|
+
advanced?: boolean;
|
|
38
|
+
auth_username?: string;
|
|
39
|
+
auth_password?: string;
|
|
40
|
+
user_agent?: string;
|
|
41
|
+
proxies?: string;
|
|
42
|
+
headers?: any;
|
|
43
|
+
rules_enabled?: boolean;
|
|
44
|
+
rules_and?: boolean;
|
|
45
|
+
rules?: INotificationRule[];
|
|
46
|
+
actions?: IPageAction[];
|
|
47
|
+
elements?: IPageElement[];
|
|
48
|
+
tags?: string[];
|
|
49
|
+
latest?: {
|
|
50
|
+
numeric: boolean;
|
|
51
|
+
contents: string | null;
|
|
52
|
+
changed_at: string | null;
|
|
53
|
+
difference: number | null;
|
|
54
|
+
human_difference: string | null;
|
|
55
|
+
three_month_difference: number | null;
|
|
56
|
+
three_month_human_difference: string | null;
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
export interface ICheck {
|
|
60
|
+
id: number;
|
|
61
|
+
status: string;
|
|
62
|
+
seen: string | null;
|
|
63
|
+
created_at: string;
|
|
64
|
+
content_type: string | null;
|
|
65
|
+
visual_diff: number | null;
|
|
66
|
+
elements: ICheckElement[];
|
|
67
|
+
}
|
|
68
|
+
export interface ICheckElement {
|
|
69
|
+
id: number;
|
|
70
|
+
contents: string | null;
|
|
71
|
+
difference: number | null;
|
|
72
|
+
hash: string;
|
|
73
|
+
changed: boolean;
|
|
74
|
+
original: string | null;
|
|
75
|
+
elements: number;
|
|
76
|
+
}
|
|
77
|
+
export interface IWebhook {
|
|
78
|
+
id?: number;
|
|
79
|
+
change_id?: number;
|
|
80
|
+
target_url: string;
|
|
81
|
+
event_type?: string;
|
|
82
|
+
payload_fields?: string[];
|
|
83
|
+
is_active?: boolean;
|
|
84
|
+
failures?: number;
|
|
85
|
+
}
|
|
86
|
+
export declare const FREQUENCIES: {
|
|
87
|
+
value: number;
|
|
88
|
+
label: string;
|
|
89
|
+
}[];
|
|
90
|
+
export declare const LOCATIONS: {
|
|
91
|
+
value: string;
|
|
92
|
+
label: string;
|
|
93
|
+
}[];
|
|
94
|
+
export declare const NOTIFICATION_CHANNELS: {
|
|
95
|
+
value: string;
|
|
96
|
+
label: string;
|
|
97
|
+
}[];
|
|
98
|
+
export declare const WEBHOOK_PAYLOAD_FIELDS: string[];
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.WEBHOOK_PAYLOAD_FIELDS = exports.NOTIFICATION_CHANNELS = exports.LOCATIONS = exports.FREQUENCIES = void 0;
|
|
4
|
+
exports.FREQUENCIES = [
|
|
5
|
+
{ value: 3, label: 'Every 3 minutes' },
|
|
6
|
+
{ value: 5, label: 'Every 5 minutes' },
|
|
7
|
+
{ value: 10, label: 'Every 10 minutes' },
|
|
8
|
+
{ value: 15, label: 'Every 15 minutes' },
|
|
9
|
+
{ value: 30, label: 'Every 30 minutes' },
|
|
10
|
+
{ value: 60, label: 'Hourly' },
|
|
11
|
+
{ value: 180, label: 'Every 3 hours' },
|
|
12
|
+
{ value: 360, label: 'Every 6 hours' },
|
|
13
|
+
{ value: 720, label: 'Every 12 hours' },
|
|
14
|
+
{ value: 1440, label: 'Daily' },
|
|
15
|
+
{ value: 2880, label: 'Every 2 days' },
|
|
16
|
+
{ value: 10080, label: 'Weekly' },
|
|
17
|
+
];
|
|
18
|
+
exports.LOCATIONS = [
|
|
19
|
+
{ value: 'random1', label: 'Random Proxy' },
|
|
20
|
+
{ value: 'lon1', label: 'London, UK' },
|
|
21
|
+
{ value: 'tor1', label: 'Toronto, CA' },
|
|
22
|
+
{ value: 'ny1', label: 'New York, US' },
|
|
23
|
+
{ value: 'fra1', label: 'Frankfurt, DE' },
|
|
24
|
+
];
|
|
25
|
+
exports.NOTIFICATION_CHANNELS = [
|
|
26
|
+
{ value: 'mail', label: 'Email' },
|
|
27
|
+
{ value: 'slack', label: 'Slack' },
|
|
28
|
+
{ value: 'discord', label: 'Discord' },
|
|
29
|
+
{ value: 'teams', label: 'Microsoft Teams' },
|
|
30
|
+
{ value: 'telegram', label: 'Telegram' },
|
|
31
|
+
];
|
|
32
|
+
exports.WEBHOOK_PAYLOAD_FIELDS = [
|
|
33
|
+
'id',
|
|
34
|
+
'title',
|
|
35
|
+
'status',
|
|
36
|
+
'content_type',
|
|
37
|
+
'visual_diff',
|
|
38
|
+
'changed_at',
|
|
39
|
+
'contents',
|
|
40
|
+
'elements',
|
|
41
|
+
'original',
|
|
42
|
+
'difference',
|
|
43
|
+
'human_difference',
|
|
44
|
+
'page_screenshot_image',
|
|
45
|
+
'text_difference_image',
|
|
46
|
+
'html_difference',
|
|
47
|
+
'markdown_difference',
|
|
48
|
+
'page',
|
|
49
|
+
'page_elements',
|
|
50
|
+
'json',
|
|
51
|
+
'json_patch',
|
|
52
|
+
'previous_check',
|
|
53
|
+
];
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { IHookFunctions, IWebhookFunctions, INodeType, INodeTypeDescription, IWebhookResponseData } from 'n8n-workflow';
|
|
2
|
+
export declare class PageCrawlTrigger implements INodeType {
|
|
3
|
+
description: INodeTypeDescription;
|
|
4
|
+
webhookMethods: {
|
|
5
|
+
default: {
|
|
6
|
+
checkExists(this: IHookFunctions): Promise<boolean>;
|
|
7
|
+
create(this: IHookFunctions): Promise<boolean>;
|
|
8
|
+
delete(this: IHookFunctions): Promise<boolean>;
|
|
9
|
+
};
|
|
10
|
+
};
|
|
11
|
+
webhook(this: IWebhookFunctions): Promise<IWebhookResponseData>;
|
|
12
|
+
}
|
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.PageCrawlTrigger = void 0;
|
|
4
|
+
const types_1 = require("../PageCrawl/types");
|
|
5
|
+
class PageCrawlTrigger {
|
|
6
|
+
constructor() {
|
|
7
|
+
this.description = {
|
|
8
|
+
displayName: 'PageCrawl Trigger',
|
|
9
|
+
name: 'pageCrawlTrigger',
|
|
10
|
+
icon: 'file:pagecrawl.svg',
|
|
11
|
+
group: ['trigger'],
|
|
12
|
+
version: 1,
|
|
13
|
+
subtitle: '=Monitor: {{$parameter["event"]}}',
|
|
14
|
+
description: 'Receive notifications when PageCrawl.io detects changes',
|
|
15
|
+
defaults: {
|
|
16
|
+
name: 'PageCrawl Trigger',
|
|
17
|
+
},
|
|
18
|
+
inputs: [],
|
|
19
|
+
outputs: ['main'],
|
|
20
|
+
credentials: [
|
|
21
|
+
{
|
|
22
|
+
name: 'pageCrawlApi',
|
|
23
|
+
required: true,
|
|
24
|
+
},
|
|
25
|
+
],
|
|
26
|
+
webhooks: [
|
|
27
|
+
{
|
|
28
|
+
name: 'default',
|
|
29
|
+
httpMethod: 'POST',
|
|
30
|
+
responseMode: 'onReceived',
|
|
31
|
+
path: 'pagecrawl',
|
|
32
|
+
},
|
|
33
|
+
],
|
|
34
|
+
properties: [
|
|
35
|
+
{
|
|
36
|
+
displayName: 'Events',
|
|
37
|
+
name: 'events',
|
|
38
|
+
type: 'multiOptions',
|
|
39
|
+
options: [
|
|
40
|
+
{
|
|
41
|
+
name: 'Change Detected',
|
|
42
|
+
value: 'change',
|
|
43
|
+
description: 'Trigger when any change is detected',
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
name: 'Error',
|
|
47
|
+
value: 'error',
|
|
48
|
+
description: 'Trigger when page check fails',
|
|
49
|
+
},
|
|
50
|
+
],
|
|
51
|
+
default: ['change'],
|
|
52
|
+
required: true,
|
|
53
|
+
description: 'The events to listen for',
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
displayName: 'Page',
|
|
57
|
+
name: 'pageId',
|
|
58
|
+
type: 'string',
|
|
59
|
+
default: '',
|
|
60
|
+
description: 'Specific page ID to monitor (leave empty for all pages)',
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
displayName: 'Payload Fields',
|
|
64
|
+
name: 'payloadFields',
|
|
65
|
+
type: 'multiOptions',
|
|
66
|
+
options: types_1.WEBHOOK_PAYLOAD_FIELDS.map((field) => ({
|
|
67
|
+
name: field.replace(/_/g, ' ').replace(/\b\w/g, (l) => l.toUpperCase()),
|
|
68
|
+
value: field,
|
|
69
|
+
})),
|
|
70
|
+
default: ['id', 'title', 'status', 'changed_at', 'difference', 'page'],
|
|
71
|
+
description: 'Fields to include in the webhook payload',
|
|
72
|
+
},
|
|
73
|
+
{
|
|
74
|
+
displayName: 'Options',
|
|
75
|
+
name: 'options',
|
|
76
|
+
type: 'collection',
|
|
77
|
+
placeholder: 'Add Option',
|
|
78
|
+
default: {},
|
|
79
|
+
options: [
|
|
80
|
+
{
|
|
81
|
+
displayName: 'Simplify Output',
|
|
82
|
+
name: 'simplify',
|
|
83
|
+
type: 'boolean',
|
|
84
|
+
default: true,
|
|
85
|
+
description: 'Whether to return simplified output format',
|
|
86
|
+
},
|
|
87
|
+
],
|
|
88
|
+
},
|
|
89
|
+
],
|
|
90
|
+
};
|
|
91
|
+
this.webhookMethods = {
|
|
92
|
+
default: {
|
|
93
|
+
async checkExists() {
|
|
94
|
+
const webhookData = this.getWorkflowStaticData('node');
|
|
95
|
+
const webhookUrl = this.getNodeWebhookUrl('default');
|
|
96
|
+
const credentials = await this.getCredentials('pageCrawlApi');
|
|
97
|
+
const baseUrl = (credentials.baseUrl || 'https://pagecrawl.io').replace(/\/+$/, '');
|
|
98
|
+
if (!webhookData.webhookId) {
|
|
99
|
+
return false;
|
|
100
|
+
}
|
|
101
|
+
try {
|
|
102
|
+
const response = await this.helpers.requestWithAuthentication.call(this, 'pageCrawlApi', {
|
|
103
|
+
method: 'GET',
|
|
104
|
+
url: `${baseUrl}/api/hooks`,
|
|
105
|
+
json: true,
|
|
106
|
+
});
|
|
107
|
+
const existingWebhook = response.find((webhook) => webhook.id === webhookData.webhookId);
|
|
108
|
+
if (!existingWebhook || existingWebhook.target_url !== webhookUrl) {
|
|
109
|
+
return false;
|
|
110
|
+
}
|
|
111
|
+
return true;
|
|
112
|
+
}
|
|
113
|
+
catch (error) {
|
|
114
|
+
return false;
|
|
115
|
+
}
|
|
116
|
+
},
|
|
117
|
+
async create() {
|
|
118
|
+
const webhookUrl = this.getNodeWebhookUrl('default');
|
|
119
|
+
const webhookData = this.getWorkflowStaticData('node');
|
|
120
|
+
const pageId = this.getNodeParameter('pageId', '');
|
|
121
|
+
const payloadFields = this.getNodeParameter('payloadFields', []);
|
|
122
|
+
const credentials = await this.getCredentials('pageCrawlApi');
|
|
123
|
+
const baseUrl = (credentials.baseUrl || 'https://pagecrawl.io').replace(/\/+$/, '');
|
|
124
|
+
const body = {
|
|
125
|
+
target_url: webhookUrl,
|
|
126
|
+
event_type: 'n8n',
|
|
127
|
+
};
|
|
128
|
+
if (pageId) {
|
|
129
|
+
body.change_id = pageId;
|
|
130
|
+
}
|
|
131
|
+
if (payloadFields.length > 0) {
|
|
132
|
+
body.payload_fields = payloadFields;
|
|
133
|
+
}
|
|
134
|
+
try {
|
|
135
|
+
const response = await this.helpers.requestWithAuthentication.call(this, 'pageCrawlApi', {
|
|
136
|
+
method: 'POST',
|
|
137
|
+
url: `${baseUrl}/api/hooks`,
|
|
138
|
+
body,
|
|
139
|
+
json: true,
|
|
140
|
+
});
|
|
141
|
+
if (!response.id) {
|
|
142
|
+
throw new Error('Failed to create webhook');
|
|
143
|
+
}
|
|
144
|
+
webhookData.webhookId = response.id;
|
|
145
|
+
return true;
|
|
146
|
+
}
|
|
147
|
+
catch (error) {
|
|
148
|
+
const errorMessage = error instanceof Error ? error.message : 'Unknown error';
|
|
149
|
+
throw new Error(`Failed to create PageCrawl webhook: ${errorMessage}`);
|
|
150
|
+
}
|
|
151
|
+
},
|
|
152
|
+
async delete() {
|
|
153
|
+
const webhookData = this.getWorkflowStaticData('node');
|
|
154
|
+
const credentials = await this.getCredentials('pageCrawlApi');
|
|
155
|
+
const baseUrl = (credentials.baseUrl || 'https://pagecrawl.io').replace(/\/+$/, '');
|
|
156
|
+
if (!webhookData.webhookId) {
|
|
157
|
+
return true;
|
|
158
|
+
}
|
|
159
|
+
try {
|
|
160
|
+
await this.helpers.requestWithAuthentication.call(this, 'pageCrawlApi', {
|
|
161
|
+
method: 'DELETE',
|
|
162
|
+
url: `${baseUrl}/api/hooks/${webhookData.webhookId}`,
|
|
163
|
+
json: true,
|
|
164
|
+
});
|
|
165
|
+
}
|
|
166
|
+
catch (error) {
|
|
167
|
+
// If webhook is already deleted, consider it a success
|
|
168
|
+
if (error.statusCode !== 404) {
|
|
169
|
+
const errorMessage = error.response?.body?.message || error.message || 'Unknown error';
|
|
170
|
+
throw new Error(`Failed to delete PageCrawl webhook: ${errorMessage}`);
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
finally {
|
|
174
|
+
// Always clean up the webhook ID, even if deletion failed
|
|
175
|
+
delete webhookData.webhookId;
|
|
176
|
+
}
|
|
177
|
+
return true;
|
|
178
|
+
},
|
|
179
|
+
},
|
|
180
|
+
};
|
|
181
|
+
}
|
|
182
|
+
async webhook() {
|
|
183
|
+
const req = this.getRequestObject();
|
|
184
|
+
const events = this.getNodeParameter('events', []);
|
|
185
|
+
const options = this.getNodeParameter('options', {});
|
|
186
|
+
const webhookData = req.body;
|
|
187
|
+
// Filter based on event type
|
|
188
|
+
if (webhookData.status === 'error' && !events.includes('error')) {
|
|
189
|
+
// Skip error events if not subscribed
|
|
190
|
+
return {
|
|
191
|
+
workflowData: [],
|
|
192
|
+
};
|
|
193
|
+
}
|
|
194
|
+
if (webhookData.status !== 'error' && !events.includes('change')) {
|
|
195
|
+
// Skip change events if not subscribed
|
|
196
|
+
return {
|
|
197
|
+
workflowData: [],
|
|
198
|
+
};
|
|
199
|
+
}
|
|
200
|
+
// Simplify output if requested
|
|
201
|
+
let responseData = webhookData;
|
|
202
|
+
if (options.simplify) {
|
|
203
|
+
responseData = {
|
|
204
|
+
id: webhookData.id,
|
|
205
|
+
title: webhookData.title,
|
|
206
|
+
status: webhookData.status,
|
|
207
|
+
changedAt: webhookData.changed_at,
|
|
208
|
+
difference: webhookData.difference,
|
|
209
|
+
humanDifference: webhookData.human_difference,
|
|
210
|
+
pageUrl: webhookData.page ? webhookData.page.url : undefined,
|
|
211
|
+
pageName: webhookData.page ? webhookData.page.name : undefined,
|
|
212
|
+
pageLink: webhookData.page ? webhookData.page.link : undefined,
|
|
213
|
+
contents: webhookData.contents,
|
|
214
|
+
};
|
|
215
|
+
}
|
|
216
|
+
return {
|
|
217
|
+
workflowData: [this.helpers.returnJsonArray(responseData)],
|
|
218
|
+
};
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
exports.PageCrawlTrigger = PageCrawlTrigger;
|