@pagecrawl/n8n-nodes-pagecrawl 0.1.2 → 0.2.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.
@@ -4,6 +4,9 @@ export declare class PageCrawl implements INodeType {
4
4
  methods: {
5
5
  listSearch: {
6
6
  pageSearch(this: ILoadOptionsFunctions, filter?: string): Promise<INodeListSearchResult>;
7
+ templateSearch(this: ILoadOptionsFunctions, filter?: string): Promise<INodeListSearchResult>;
8
+ workspaceSearch(this: ILoadOptionsFunctions, filter?: string): Promise<INodeListSearchResult>;
9
+ authSearch(this: ILoadOptionsFunctions, filter?: string): Promise<INodeListSearchResult>;
7
10
  };
8
11
  };
9
12
  execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]>;
@@ -97,6 +97,60 @@ class PageCrawl {
97
97
  }
98
98
  return { results };
99
99
  },
100
+ async templateSearch(filter) {
101
+ const baseUrl = 'https://pagecrawl.io';
102
+ const response = await this.helpers.httpRequestWithAuthentication.call(this, 'pageCrawlApi', {
103
+ method: 'GET',
104
+ url: `${baseUrl}/api/templates`,
105
+ json: true,
106
+ });
107
+ const templates = response.data || response;
108
+ let results = templates.map((template) => ({
109
+ name: template.name || `Template ${template.id}`,
110
+ value: String(template.id),
111
+ }));
112
+ if (filter) {
113
+ const filterLower = filter.toLowerCase();
114
+ results = results.filter((t) => t.name.toLowerCase().includes(filterLower));
115
+ }
116
+ return { results };
117
+ },
118
+ async workspaceSearch(filter) {
119
+ const baseUrl = 'https://pagecrawl.io';
120
+ const response = await this.helpers.httpRequestWithAuthentication.call(this, 'pageCrawlApi', {
121
+ method: 'GET',
122
+ url: `${baseUrl}/api/workspaces`,
123
+ json: true,
124
+ });
125
+ const workspaces = response.data || response;
126
+ let results = workspaces.map((workspace) => ({
127
+ name: workspace.name || `Workspace ${workspace.id}`,
128
+ value: String(workspace.id),
129
+ }));
130
+ if (filter) {
131
+ const filterLower = filter.toLowerCase();
132
+ results = results.filter((w) => w.name.toLowerCase().includes(filterLower));
133
+ }
134
+ return { results };
135
+ },
136
+ async authSearch(filter) {
137
+ const baseUrl = 'https://pagecrawl.io';
138
+ const response = await this.helpers.httpRequestWithAuthentication.call(this, 'pageCrawlApi', {
139
+ method: 'GET',
140
+ url: `${baseUrl}/api/auths`,
141
+ json: true,
142
+ });
143
+ const auths = response.data || response;
144
+ let results = auths.map((auth) => ({
145
+ name: auth.name || `Auth ${auth.id}`,
146
+ value: String(auth.id),
147
+ }));
148
+ if (filter) {
149
+ const filterLower = filter.toLowerCase();
150
+ results = results.filter((a) => a.name.toLowerCase().includes(filterLower));
151
+ }
152
+ return { results };
153
+ },
100
154
  },
101
155
  };
102
156
  }
@@ -109,6 +163,17 @@ class PageCrawl {
109
163
  const pageLocator = this.getNodeParameter('pageId', index);
110
164
  return pageLocator.value || '';
111
165
  };
166
+ // Helper to transform fixedCollection to array
167
+ const transformFixedCollection = (collection, key) => {
168
+ if (!collection)
169
+ return [];
170
+ if (Array.isArray(collection))
171
+ return collection;
172
+ if (typeof collection === 'object' && collection[key]) {
173
+ return collection[key];
174
+ }
175
+ return [];
176
+ };
112
177
  for (let i = 0; i < items.length; i++) {
113
178
  const resource = this.getNodeParameter('resource', i);
114
179
  const operation = this.getNodeParameter('operation', i);
@@ -162,8 +227,12 @@ class PageCrawl {
162
227
  }
163
228
  else if (operation === 'createSimple') {
164
229
  const url = this.getNodeParameter('url', i);
230
+ const name = this.getNodeParameter('name', i, '');
165
231
  const additionalFields = this.getNodeParameter('additionalFields', i);
166
232
  const body = { url };
233
+ if (name) {
234
+ body.name = name;
235
+ }
167
236
  if (additionalFields.selector) {
168
237
  body.selector = additionalFields.selector;
169
238
  }
@@ -198,14 +267,34 @@ class PageCrawl {
198
267
  if (typeof body.tags === 'string' && body.tags) {
199
268
  body.tags = body.tags.split(',').map((tag) => tag.trim()).filter(Boolean);
200
269
  }
201
- // Remove ID fields if they're 0 (not set)
202
- if (body.folder_id === 0)
270
+ // Extract values from resourceLocator fields
271
+ if (body.folder_id && typeof body.folder_id === 'object') {
272
+ body.folder_id = body.folder_id.value || '';
273
+ }
274
+ if (body.template_id && typeof body.template_id === 'object') {
275
+ body.template_id = body.template_id.value || '';
276
+ }
277
+ if (body.auth_id && typeof body.auth_id === 'object') {
278
+ body.auth_id = body.auth_id.value || '';
279
+ }
280
+ // Remove ID fields if empty or 0 (not set)
281
+ if (!body.folder_id || body.folder_id === 0)
203
282
  delete body.folder_id;
204
- if (body.template_id === 0)
283
+ if (!body.template_id || body.template_id === 0)
205
284
  delete body.template_id;
206
- if (body.auth_id === 0)
285
+ if (!body.auth_id || body.auth_id === 0)
207
286
  delete body.auth_id;
208
- // Parse JSON fields if they're strings
287
+ // Transform fixedCollection fields to arrays
288
+ if (body.actions && typeof body.actions === 'object') {
289
+ body.actions = transformFixedCollection(body.actions, 'action');
290
+ }
291
+ if (body.rules && typeof body.rules === 'object') {
292
+ body.rules = transformFixedCollection(body.rules, 'rule');
293
+ if (body.rules.length > 0) {
294
+ body.rules_enabled = true;
295
+ }
296
+ }
297
+ // Parse JSON fields if they're strings (backwards compatibility)
209
298
  if (typeof body.actions === 'string') {
210
299
  try {
211
300
  body.actions = JSON.parse(body.actions);
@@ -246,12 +335,22 @@ class PageCrawl {
246
335
  if (typeof body.tags === 'string' && body.tags) {
247
336
  body.tags = body.tags.split(',').map((tag) => tag.trim()).filter(Boolean);
248
337
  }
249
- // Remove ID fields if they're 0 (not set)
250
- if (body.folder_id === 0)
338
+ // Extract values from resourceLocator fields
339
+ if (body.folder_id && typeof body.folder_id === 'object') {
340
+ body.folder_id = body.folder_id.value || '';
341
+ }
342
+ if (body.template_id && typeof body.template_id === 'object') {
343
+ body.template_id = body.template_id.value || '';
344
+ }
345
+ if (body.auth_id && typeof body.auth_id === 'object') {
346
+ body.auth_id = body.auth_id.value || '';
347
+ }
348
+ // Remove ID fields if empty or 0 (not set)
349
+ if (!body.folder_id || body.folder_id === 0)
251
350
  delete body.folder_id;
252
- if (body.template_id === 0)
351
+ if (!body.template_id || body.template_id === 0)
253
352
  delete body.template_id;
254
- if (body.auth_id === 0)
353
+ if (!body.auth_id || body.auth_id === 0)
255
354
  delete body.auth_id;
256
355
  // Parse JSON fields if they're strings
257
356
  if (typeof body.elements === 'string') {
@@ -262,6 +361,17 @@ class PageCrawl {
262
361
  throw new n8n_workflow_1.NodeOperationError(this.getNode(), 'Invalid JSON in elements field', { itemIndex: i });
263
362
  }
264
363
  }
364
+ // Transform fixedCollection fields to arrays
365
+ if (body.actions && typeof body.actions === 'object') {
366
+ body.actions = transformFixedCollection(body.actions, 'action');
367
+ }
368
+ if (body.rules && typeof body.rules === 'object') {
369
+ body.rules = transformFixedCollection(body.rules, 'rule');
370
+ if (body.rules.length > 0) {
371
+ body.rules_enabled = true;
372
+ }
373
+ }
374
+ // Parse JSON fields if they're strings (backwards compatibility)
265
375
  if (typeof body.actions === 'string') {
266
376
  try {
267
377
  body.actions = JSON.parse(body.actions);
@@ -310,7 +420,7 @@ class PageCrawl {
310
420
  qs.skip_first_notification = 1;
311
421
  }
312
422
  responseData = await this.helpers.httpRequestWithAuthentication.call(this, 'pageCrawlApi', {
313
- method: 'PUT',
423
+ method: 'POST',
314
424
  url: `${baseUrl}/api/pages/${pageId}/check`,
315
425
  qs,
316
426
  json: true,
@@ -381,24 +491,23 @@ class PageCrawl {
381
491
  }
382
492
  else if (resource === 'screenshot') {
383
493
  const pageId = getPageId(i);
494
+ const checkId = this.getNodeParameter('checkId', i, 'latest');
384
495
  let endpoint = '';
385
- if (operation === 'getLatest') {
386
- endpoint = `/pages/${pageId}/checks/latest/screenshot`;
387
- }
388
- else if (operation === 'getLatestDiff') {
389
- endpoint = `/pages/${pageId}/checks/latest/diff`;
390
- }
391
- else if (operation === 'getCheckScreenshot') {
392
- const checkId = this.getNodeParameter('checkId', i);
496
+ if (operation === 'getScreenshot') {
393
497
  endpoint = `/pages/${pageId}/checks/${checkId}/screenshot`;
394
498
  }
395
- else if (operation === 'getCheckDiff') {
396
- const checkId = this.getNodeParameter('checkId', i);
499
+ else if (operation === 'getScreenshotDiff') {
397
500
  endpoint = `/pages/${pageId}/checks/${checkId}/diff`;
398
501
  }
502
+ const previous = operation === 'getScreenshot' ? this.getNodeParameter('previous', i, false) : false;
503
+ const qs = {};
504
+ if (previous) {
505
+ qs.previous = 1;
506
+ }
399
507
  const response = await this.helpers.httpRequestWithAuthentication.call(this, 'pageCrawlApi', {
400
508
  method: 'GET',
401
509
  url: `${baseUrl}/api${endpoint}`,
510
+ qs,
402
511
  encoding: 'arraybuffer',
403
512
  });
404
513
  const binaryData = await this.helpers.prepareBinaryData(response, `screenshot-${pageId}.png`, 'image/png');
@@ -56,7 +56,7 @@ exports.checkFields = [
56
56
  },
57
57
  },
58
58
  default: { mode: 'list', value: '' },
59
- description: 'Select a page or enter slug/ID. <a href="https://pagecrawl.io/app/pages" target="_blank">View pages</a>.',
59
+ description: 'Select a page or enter slug/ID. Find the slug in your page URL (pagecrawl.io/app/pages/{slug}). Enable Debug mode in Settings to see page IDs.',
60
60
  modes: [
61
61
  {
62
62
  displayName: 'From List',
@@ -116,14 +116,14 @@ exports.checkFields = [
116
116
  displayName: 'Simple',
117
117
  name: 'simple',
118
118
  type: 'boolean',
119
- default: false,
119
+ default: true,
120
120
  description: 'Whether to return simplified response',
121
121
  },
122
122
  {
123
123
  displayName: 'Take',
124
124
  name: 'take',
125
125
  type: 'number',
126
- default: 0,
126
+ default: 2,
127
127
  description: 'Limit number of checks retrieved',
128
128
  typeOptions: {
129
129
  minValue: 0,
@@ -138,14 +138,13 @@ exports.checkFields = [
138
138
  displayName: 'Check ID',
139
139
  name: 'checkId',
140
140
  type: 'string',
141
- required: true,
142
141
  displayOptions: {
143
142
  show: {
144
143
  resource: ['check'],
145
144
  operation: ['getDiffHtml', 'getDiffImage', 'getDiffMarkdown'],
146
145
  },
147
146
  },
148
- default: '',
149
- description: 'The check ID (use "latest" for most recent)',
147
+ default: 'latest',
148
+ description: 'The check ID to get diff for (defaults to "latest" for most recent)',
150
149
  },
151
150
  ];