n8n-nodes-linkedin-scraper 1.0.21 → 1.0.22
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/dist/nodes/LinkedinScraper/LinkedinScraper.node.js +15 -11
- package/dist/nodes/LinkedinScraper/LinkedinScraper.node.js.map +1 -1
- package/dist/package.json +1 -1
- package/dist/test/LinkedinScraper.node.test.js +65 -0
- package/dist/test/LinkedinScraper.node.test.js.map +1 -1
- package/package.json +1 -1
|
@@ -266,17 +266,21 @@ class LinkedinScraper {
|
|
|
266
266
|
message: 'InNotes API credentials are missing',
|
|
267
267
|
});
|
|
268
268
|
}
|
|
269
|
-
//
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
269
|
+
// No authMethod check here, deliberately. The InNotes credential used to
|
|
270
|
+
// offer a choice between a Bearer token and username/password, and this
|
|
271
|
+
// node refused anything that was not 'token'. 3b8c1e46 deleted the
|
|
272
|
+
// username/password auth and the authMethod field along with it — but
|
|
273
|
+
// only from the credential, in n8n_node/. This file was never touched,
|
|
274
|
+
// so the guard went on reading a property that no longer exists and no
|
|
275
|
+
// longer can: the field is gone from the credential type, so nothing
|
|
276
|
+
// writes it and the n8n UI has no way to set it.
|
|
277
|
+
//
|
|
278
|
+
// The failure was total for any credential that did not happen to carry
|
|
279
|
+
// the value left over from before, and the message sent people to go and
|
|
280
|
+
// select an option that is no longer on the screen. The only thing this
|
|
281
|
+
// node actually needs is the token.
|
|
282
|
+
// Author: Marco — 2026-08-05
|
|
283
|
+
const bearerToken = credentials.token;
|
|
280
284
|
if (!bearerToken) {
|
|
281
285
|
throw new n8n_workflow_1.NodeApiError(this.getNode(), {
|
|
282
286
|
message: 'Bearer token is missing from InNotes API credentials',
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../nodes/LinkedinScraper/LinkedinScraper.node.ts"],"names":[],"mappings":";AAAA;;;;;;GAMG;;;AAEH,+CAOsB;AAEtB,SAAS,mBAAmB,CAAC,KAAa;IACzC,OAAO,KAAK;SACV,KAAK,CAAC,GAAG,CAAC;SACV,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC;SAC5B,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;AACvC,CAAC;AAED,MAAa,eAAe;IAA5B;QACC,gBAAW,GAAyB;YACnC,WAAW,EAAE,0BAA0B;YACvC,IAAI,EAAE,iBAAiB;YACvB,KAAK,EAAE,CAAC,WAAW,CAAC;YACpB,OAAO,EAAE,CAAC;YACV,WAAW,EAAE,iDAAiD;YAC9D,QAAQ,EAAE,8DAA8D;YACxE,IAAI,EAAE,eAAe;YACrB,QAAQ,EAAE;gBACT,IAAI,EAAE,kBAAkB;aACxB;YACD,MAAM,EAAE,CAAC,MAAM,CAAC;YAChB,OAAO,EAAE,CAAC,MAAM,CAAC;YACjB,WAAW,EAAE;gBACZ;oBACC,yCAAyC;oBACzC,IAAI,EAAE,YAAY;oBAClB,QAAQ,EAAE,IAAI;iBACd;aACD;YACD,UAAU,EAAE;gBACX,qBAAqB;gBACrB;oBACC,WAAW,EAAE,UAAU;oBACvB,IAAI,EAAE,UAAU;oBAChB,IAAI,EAAE,SAAS;oBACf,gBAAgB,EAAE,IAAI;oBACtB,OAAO,EAAE;wBACR;4BACC,IAAI,EAAE,MAAM;4BACZ,KAAK,EAAE,MAAM;yBACb;wBACD;4BACC,IAAI,EAAE,KAAK;4BACX,KAAK,EAAE,KAAK;yBACZ;wBACD;4BACC,IAAI,EAAE,SAAS;4BACf,KAAK,EAAE,SAAS;yBAChB;qBACD;oBACD,OAAO,EAAE,MAAM;iBACf;gBACD,kBAAkB;gBAClB;oBACC,WAAW,EAAE,WAAW;oBACxB,IAAI,EAAE,WAAW;oBACjB,IAAI,EAAE,SAAS;oBACf,cAAc,EAAE;wBACf,IAAI,EAAE;4BACL,QAAQ,EAAE,CAAC,MAAM,CAAC;yBAClB;qBACD;oBACD,OAAO,EAAE;wBACR;4BACC,IAAI,EAAE,QAAQ;4BACd,KAAK,EAAE,QAAQ;4BACf,MAAM,EAAE,yCAAyC;yBACjD;qBACD;oBACD,OAAO,EAAE,QAAQ;iBACjB;gBACD,iBAAiB;gBACjB;oBACC,WAAW,EAAE,WAAW;oBACxB,IAAI,EAAE,WAAW;oBACjB,IAAI,EAAE,SAAS;oBACf,cAAc,EAAE;wBACf,IAAI,EAAE;4BACL,QAAQ,EAAE,CAAC,KAAK,CAAC;yBACjB;qBACD;oBACD,OAAO,EAAE;wBACR;4BACC,IAAI,EAAE,SAAS;4BACf,KAAK,EAAE,SAAS;4BAChB,MAAM,EAAE,mBAAmB;yBAC3B;qBACD;oBACD,OAAO,EAAE,SAAS;iBAClB;gBACD,qBAAqB;gBACrB;oBACC,WAAW,EAAE,WAAW;oBACxB,IAAI,EAAE,WAAW;oBACjB,IAAI,EAAE,SAAS;oBACf,cAAc,EAAE;wBACf,IAAI,EAAE;4BACL,QAAQ,EAAE,CAAC,SAAS,CAAC;yBACrB;qBACD;oBACD,OAAO,EAAE;wBACR;4BACC,IAAI,EAAE,WAAW;4BACjB,KAAK,EAAE,WAAW;4BAClB,MAAM,EAAE,8BAA8B;yBACtC;qBACD;oBACD,OAAO,EAAE,WAAW;iBACpB;gBACD,yBAAyB;gBACzB;oBACC,WAAW,EAAE,YAAY;oBACzB,IAAI,EAAE,WAAW;oBACjB,IAAI,EAAE,QAAQ;oBACd,OAAO,EAAE,EAAE;oBACX,WAAW,EAAE,8BAA8B;oBAC3C,WAAW,EAAE,kDAAkD;oBAC/D,cAAc,EAAE;wBACf,IAAI,EAAE;4BACL,QAAQ,EAAE,CAAC,MAAM,CAAC;4BAClB,SAAS,EAAE,CAAC,QAAQ,CAAC;yBACrB;qBACD;oBACD,QAAQ,EAAE,IAAI;iBACd;gBACD;oBACC,WAAW,EAAE,WAAW;oBACxB,IAAI,EAAE,WAAW;oBACjB,IAAI,EAAE,QAAQ;oBACd,OAAO,EAAE,EAAE;oBACX,WAAW,EAAE,gBAAgB;oBAC7B,WAAW,EAAE,gDAAgD;oBAC7D,cAAc,EAAE;wBACf,IAAI,EAAE;4BACL,QAAQ,EAAE,CAAC,MAAM,CAAC;4BAClB,SAAS,EAAE,CAAC,QAAQ,CAAC;yBACrB;qBACD;oBACD,QAAQ,EAAE,IAAI;iBACd;gBACD;oBACC,WAAW,EAAE,aAAa;oBAC1B,IAAI,EAAE,YAAY;oBAClB,IAAI,EAAE,QAAQ;oBACd,OAAO,EAAE,GAAG;oBACZ,WAAW,EAAE;wBACZ,QAAQ,EAAE,CAAC;wBACX,QAAQ,EAAE,IAAI;qBACd;oBACD,cAAc,EAAE;wBACf,IAAI,EAAE;4BACL,QAAQ,EAAE,CAAC,MAAM,CAAC;4BAClB,SAAS,EAAE,CAAC,QAAQ,CAAC;yBACrB;qBACD;iBACD;gBACD;oBACC,WAAW,EAAE,iBAAiB;oBAC9B,IAAI,EAAE,eAAe;oBACrB,IAAI,EAAE,SAAS;oBACf,OAAO,EAAE,IAAI;oBACb,cAAc,EAAE;wBACf,IAAI,EAAE;4BACL,QAAQ,EAAE,CAAC,MAAM,CAAC;4BAClB,SAAS,EAAE,CAAC,QAAQ,CAAC;yBACrB;qBACD;iBACD;gBACD;oBACC,WAAW,EAAE,YAAY;oBACzB,IAAI,EAAE,WAAW;oBACjB,IAAI,EAAE,SAAS;oBACf,OAAO,EAAE;wBACR,EAAE,IAAI,EAAE,eAAe,EAAE,KAAK,EAAE,QAAQ,EAAE;wBAC1C,EAAE,IAAI,EAAE,WAAW,EAAE,KAAK,EAAE,SAAS,EAAE;wBACvC,EAAE,IAAI,EAAE,YAAY,EAAE,KAAK,EAAE,UAAU,EAAE;qBACzC;oBACD,OAAO,EAAE,QAAQ;oBACjB,WAAW,EAAE,6BAA6B;oBAC1C,cAAc,EAAE;wBACf,IAAI,EAAE;4BACL,QAAQ,EAAE,CAAC,MAAM,CAAC;4BAClB,SAAS,EAAE,CAAC,QAAQ,CAAC;yBACrB;qBACD;iBACD;gBACD;oBACC,WAAW,EAAE,mBAAmB;oBAChC,IAAI,EAAE,kBAAkB;oBACxB,IAAI,EAAE,QAAQ;oBACd,OAAO,EAAE,EAAE;oBACX,WAAW,EAAE,sBAAsB;oBACnC,WAAW,EAAE,8CAA8C;oBAC3D,cAAc,EAAE;wBACf,IAAI,EAAE;4BACL,QAAQ,EAAE,CAAC,MAAM,CAAC;4BAClB,SAAS,EAAE,CAAC,QAAQ,CAAC;yBACrB;qBACD;iBACD;gBACD;oBACC,WAAW,EAAE,mBAAmB;oBAChC,IAAI,EAAE,kBAAkB;oBACxB,IAAI,EAAE,QAAQ;oBACd,OAAO,EAAE,EAAE;oBACX,WAAW,EAAE,cAAc;oBAC3B,WAAW,EAAE,6DAA6D;oBAC1E,cAAc,EAAE;wBACf,IAAI,EAAE;4BACL,QAAQ,EAAE,CAAC,MAAM,CAAC;4BAClB,SAAS,EAAE,CAAC,QAAQ,CAAC;yBACrB;qBACD;iBACD;gBACD,yBAAyB;gBACzB;oBACC,WAAW,EAAE,SAAS;oBACtB,IAAI,EAAE,QAAQ;oBACd,IAAI,EAAE,QAAQ;oBACd,OAAO,EAAE,EAAE;oBACX,WAAW,EAAE,6BAA6B;oBAC1C,cAAc,EAAE;wBACf,IAAI,EAAE;4BACL,QAAQ,EAAE,CAAC,KAAK,CAAC;4BACjB,SAAS,EAAE,CAAC,SAAS,CAAC;yBACtB;qBACD;oBACD,QAAQ,EAAE,IAAI;iBACd;gBACD,qBAAqB;gBACrB;oBACC,WAAW,EAAE,aAAa;oBAC1B,IAAI,EAAE,YAAY;oBAClB,IAAI,EAAE,QAAQ;oBACd,OAAO,EAAE,EAAE;oBACX,WAAW,EAAE,sBAAsB;oBACnC,cAAc,EAAE;wBACf,IAAI,EAAE;4BACL,QAAQ,EAAE,CAAC,SAAS,CAAC;4BACrB,SAAS,EAAE,CAAC,WAAW,CAAC;yBACxB;qBACD;oBACD,QAAQ,EAAE,IAAI;iBACd;aACD;SACD,CAAC;IAqVH,CAAC;IAnVA,KAAK,CAAC,OAAO;;QACZ,MAAM,KAAK,GAAG,IAAI,CAAC,YAAY,EAAE,CAAC;QAClC,MAAM,UAAU,GAAkB,EAAE,CAAC;QAErC,kEAAkE;QAClE,MAAM,WAAW,GAAG,CAAC,MAAM,IAAI,CAAC,cAAc,CAAC,YAAY,CAAC,CAAuB,CAAC;QAEpF,IAAI,CAAC,WAAW,EAAE,CAAC;YAClB,MAAM,IAAI,2BAAY,CAAC,IAAI,CAAC,OAAO,EAAE,EAAE;gBACtC,OAAO,EAAE,qCAAqC;aAC9C,CAAC,CAAC;QACJ,CAAC;QAED,wCAAwC;QACxC,MAAM,UAAU,GAAG,WAAW,CAAC,UAAoB,CAAC;QACpD,IAAI,WAA+B,CAAC;QAEpC,IAAI,UAAU,KAAK,OAAO,EAAE,CAAC;YAC5B,WAAW,GAAG,WAAW,CAAC,KAAe,CAAC;QAC3C,CAAC;aAAM,CAAC;YACP,MAAM,IAAI,2BAAY,CAAC,IAAI,CAAC,OAAO,EAAE,EAAE;gBACtC,OAAO,EAAE,wHAAwH;aACjI,CAAC,CAAC;QACJ,CAAC;QAED,IAAI,CAAC,WAAW,EAAE,CAAC;YAClB,MAAM,IAAI,2BAAY,CAAC,IAAI,CAAC,OAAO,EAAE,EAAE;gBACtC,OAAO,EAAE,sDAAsD;aAC/D,CAAC,CAAC;QACJ,CAAC;QAED,KAAK,IAAI,SAAS,GAAG,CAAC,EAAE,SAAS,GAAG,KAAK,CAAC,MAAM,EAAE,SAAS,EAAE,EAAE,CAAC;YAC/D,MAAM,UAAU,GAAG,4BAA4B,CAAC;YAChD,MAAM,QAAQ,GAAG,IAAI,CAAC,gBAAgB,CAAC,UAAU,EAAE,SAAS,CAAW,CAAC;YACxE,MAAM,SAAS,GAAG,IAAI,CAAC,gBAAgB,CAAC,WAAW,EAAE,SAAS,CAAW,CAAC;YAE1E,IAAI,CAAC;gBACJ,IAAI,QAAQ,KAAK,MAAM,IAAI,SAAS,KAAK,QAAQ,EAAE,CAAC;oBACnD,MAAM,SAAS,GAAG,mBAAmB,CACpC,IAAI,CAAC,gBAAgB,CAAC,WAAW,EAAE,SAAS,CAAW,CACvD,CAAC;oBACF,MAAM,SAAS,GAAG,mBAAmB,CACpC,IAAI,CAAC,gBAAgB,CAAC,WAAW,EAAE,SAAS,CAAW,CACvD,CAAC;oBACF,MAAM,UAAU,GAAG,IAAI,CAAC,gBAAgB,CAAC,YAAY,EAAE,SAAS,CAAW,CAAC;oBAC5E,MAAM,aAAa,GAAG,IAAI,CAAC,gBAAgB,CAAC,eAAe,EAAE,SAAS,CAAY,CAAC;oBACnF,MAAM,SAAS,GAAG,IAAI,CAAC,gBAAgB,CAAC,WAAW,EAAE,SAAS,CAAW,CAAC;oBAC1E,MAAM,gBAAgB,GAAG,mBAAmB,CAC1C,IAAI,CAAC,gBAAgB,CAAC,kBAAkB,EAAE,SAAS,CAAY,IAAI,EAAE,CACtE,CAAC;oBACF,MAAM,gBAAgB,GAAG,mBAAmB,CAC1C,IAAI,CAAC,gBAAgB,CAAC,kBAAkB,EAAE,SAAS,CAAY,IAAI,EAAE,CACtE,CAAC;oBAEF,4DAA4D;oBAC5D,0DAA0D;oBAC1D,0DAA0D;oBAC1D,4DAA4D;oBAC5D,yDAAyD;oBACzD,EAAE;oBACF,2DAA2D;oBAC3D,sDAAsD;oBACtD,yDAAyD;oBACzD,iDAAiD;oBACjD,MAAM,WAAW,GAAgB;wBAChC,UAAU,EAAE,SAAS;wBACrB,SAAS;wBACT,WAAW,EAAE,UAAU;wBACvB,eAAe,EAAE,aAAa;wBAC9B,UAAU,EAAE,SAAS;wBACrB,iBAAiB,EAAE,gBAAgB;wBACnC,kBAAkB,EAAE,gBAAgB;qBACpC,CAAC;oBAEF,kBAAkB;oBAClB,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC;wBAC3C,MAAM,EAAE,MAAM;wBACd,GAAG,EAAE,GAAG,UAAU,cAAc;wBAChC,OAAO,EAAE;4BACR,eAAe,EAAE,UAAU,WAAW,EAAE;4BACxC,cAAc,EAAE,kBAAkB;yBAClC;wBACD,IAAI,EAAE,WAAW;wBACjB,IAAI,EAAE,IAAI;wBACV,OAAO,EAAE,EAAE,GAAC,EAAE,GAAC,IAAI;qBACnB,CAAC,CAAC;oBAEH,MAAM,IAAI,GAAI,QAAwB,CAAC,IAAqB,CAAC;oBAC7D,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC;wBAC1B,MAAM,IAAI,2BAAY,CAAC,IAAI,CAAC,OAAO,EAAE,EAAE;4BACtC,OAAO,EAAE,4CAA4C;yBACrD,CAAC,CAAC;oBACJ,CAAC;oBAED,kDAAkD;oBAClD,MAAM,SAAS,GAAG,IAAI,GAAG,EAAU,CAAC;oBACpC,MAAM,UAAU,GAAkB,EAAE,CAAC;oBACrC,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;wBACxB,MAAM,IAAI,GAAI,GAAG,CAAC,IAAe,IAAI,EAAE,CAAC;wBACxC,IAAI,IAAI,IAAI,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;4BACjC,SAAS;wBACV,CAAC;wBACD,IAAI,IAAI,EAAE,CAAC;4BACV,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;wBACrB,CAAC;wBACD,UAAU,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;oBACtB,CAAC;oBACD,MAAM,iBAAiB,GAAG,IAAI,CAAC,MAAM,GAAG,UAAU,CAAC,MAAM,CAAC;oBAC1D,OAAO,CAAC,GAAG,CAAC,yBAAyB,iBAAiB,oBAAoB,IAAI,CAAC,MAAM,UAAU,CAAC,CAAC;oBACjG,UAAU,CAAC,IAAI,CAAC,GAAG,UAAU,CAAC,CAAC;oBAC/B,SAAS;gBACV,CAAC;gBAED,IAAI,QAAQ,KAAK,KAAK,IAAI,SAAS,KAAK,SAAS,EAAE,CAAC;oBACpD,0EAA0E;oBACzE,MAAM,UAAU,GAAG,EAAE,CAAC;oBAEtB,8DAA8D;oBAC9D,IAAI,SAAS,GAAG,CAAC,EAAE,CAAC;wBACnB,SAAS;oBACV,CAAC;oBAOF,MAAM,SAAS,GAAmB,EAAE,CAAC;oBACrC,MAAM,cAAc,GAAkB,EAAE,CAAC;oBAEzC,mCAAmC;oBACnC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;wBACvC,MAAM,MAAM,GAAG,IAAI,CAAC,gBAAgB,CAAC,QAAQ,EAAE,CAAC,CAAW,CAAC;wBAE5D,IAAI,MAAM,aAAN,MAAM,uBAAN,MAAM,CAAE,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC;4BAChC,SAAS,CAAC,IAAI,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC,CAAC;wBAC3C,CAAC;6BAAM,CAAC;4BACP,2CAA2C;4BAC3C,cAAc,CAAC,IAAI,CAAC;gCACnB,OAAO,EAAE,KAAK;gCACd,KAAK,EAAE,oBAAoB,MAAM,IAAI,OAAO,EAAE;gCAC9C,cAAc,EAAE,CAAC;6BACjB,CAAC,CAAC;wBACJ,CAAC;oBACF,CAAC;oBAED,+BAA+B;oBAC/B,MAAM,YAAY,GAAkB,EAAE,CAAC;oBAEvC,KAAK,IAAI,UAAU,GAAG,CAAC,EAAE,UAAU,GAAG,SAAS,CAAC,MAAM,EAAE,UAAU,IAAI,UAAU,EAAE,CAAC;wBAClF,MAAM,KAAK,GAAG,SAAS,CAAC,KAAK,CAAC,UAAU,EAAE,UAAU,GAAG,UAAU,CAAC,CAAC;wBACnE,MAAM,SAAS,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;wBAE1C,IAAI,CAAC;4BACJ,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC;gCAC3C,MAAM,EAAE,MAAM;gCACd,GAAG,EAAE,GAAG,UAAU,qBAAqB;gCACvC,OAAO,EAAE;oCACR,aAAa,EAAE,UAAU,WAAW,EAAE;oCACtC,cAAc,EAAE,kBAAkB;iCAClC;gCACD,IAAI,EAAE;oCACL,IAAI,EAAE,SAAS;oCACf,cAAc,EAAE,CAAC;oCACjB,WAAW,EAAE,CAAC;iCACd;gCACD,IAAI,EAAE,IAAI;gCACV,OAAO,EAAE,EAAE,GAAG,EAAE,GAAG,IAAI,EAAE,+CAA+C;6BACxE,CAAC,CAAC;4BAEH,gDAAgD;4BAChD,MAAM,OAAO,GAAI,QAAwB,CAAC,OAAwB,CAAC;4BACnE,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;gCACzC,MAAM,MAAM,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;gCAC1B,YAAY,CAAC,IAAI,CAAC;oCACjB,GAAG,MAAM;oCACT,cAAc,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK;iCAC9B,CAAC,CAAC;4BACJ,CAAC;wBACF,CAAC;wBAAC,OAAO,GAAG,EAAE,CAAC;4BACd,yCAAyC;4BACzC,MAAM,UAAU,GAAI,GAAW,CAAC,UAAU,CAAC;4BAC3C,MAAM,MAAM,GAAI,GAAa,CAAC,OAAO,IAAI,EAAE,CAAC;4BAC5C,IAAI,UAAU,KAAK,GAAG,IAAI,UAAU,KAAK,GAAG,IAAI,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;gCAClG,MAAM,GAAG,CAAC;4BACX,CAAC;4BACD,0DAA0D;4BAC1D,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;gCAC1B,YAAY,CAAC,IAAI,CAAC;oCACjB,OAAO,EAAE,KAAK;oCACd,KAAK,EAAE,yBAA0B,GAAa,CAAC,OAAO,EAAE;oCACxD,GAAG,EAAE,IAAI,CAAC,GAAG;oCACb,cAAc,EAAE,IAAI,CAAC,KAAK;iCAC1B,CAAC,CAAC;4BACJ,CAAC;wBACF,CAAC;oBACF,CAAC;oBAED,8EAA8E;oBAC9E,MAAM,UAAU,GAAG,CAAC,GAAG,cAAc,EAAE,GAAG,YAAY,CAAC,CAAC;oBACxD,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAE,CAAC,CAAC,cAAyB,GAAI,CAAC,CAAC,cAAyB,CAAC,CAAC;oBAEvF,6DAA6D;oBAC7D,KAAK,MAAM,MAAM,IAAI,UAAU,EAAE,CAAC;wBACjC,MAAM,EAAE,cAAc,EAAE,CAAC,EAAE,GAAG,WAAW,EAAE,GAAG,MAAM,CAAC;wBACrD,UAAU,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;oBAC9B,CAAC;oBAED,uDAAuD;oBACvD,MAAM;gBACN,CAAC;gBAED,IAAI,QAAQ,KAAK,SAAS,IAAI,SAAS,KAAK,WAAW,EAAE,CAAC;oBAC1D,0EAA0E;oBACzE,MAAM,UAAU,GAAG,EAAE,CAAC;oBAEtB,8DAA8D;oBAC9D,IAAI,SAAS,GAAG,CAAC,EAAE,CAAC;wBACnB,SAAS;oBACV,CAAC;oBAOD,MAAM,SAAS,GAAmB,EAAE,CAAC;oBACrC,MAAM,cAAc,GAAkB,EAAE,CAAC;oBAEzC,mCAAmC;oBACnC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;wBACvC,MAAM,UAAU,GAAG,IAAI,CAAC,gBAAgB,CAAC,YAAY,EAAE,CAAC,CAAW,CAAC;wBAEpE,IAAI,UAAU,aAAV,UAAU,uBAAV,UAAU,CAAE,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC;4BACpC,SAAS,CAAC,IAAI,CAAC,EAAE,GAAG,EAAE,UAAU,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC,CAAC;wBAC/C,CAAC;6BAAM,CAAC;4BACP,2CAA2C;4BAC3C,cAAc,CAAC,IAAI,CAAC;gCACnB,cAAc,EAAE,CAAC;gCACjB,MAAM,EAAE,SAAS;gCACjB,OAAO,EAAE,KAAK;gCACd,KAAK,EAAE,wBAAwB,UAAU,IAAI,OAAO,EAAE;gCACtD,cAAc,EAAE,CAAC;6BACjB,CAAC,CAAC;wBACJ,CAAC;oBACF,CAAC;oBAED,+BAA+B;oBAC/B,MAAM,YAAY,GAAkB,EAAE,CAAC;oBAEvC,KAAK,IAAI,UAAU,GAAG,CAAC,EAAE,UAAU,GAAG,SAAS,CAAC,MAAM,EAAE,UAAU,IAAI,UAAU,EAAE,CAAC;wBAClF,MAAM,KAAK,GAAG,SAAS,CAAC,KAAK,CAAC,UAAU,EAAE,UAAU,GAAG,UAAU,CAAC,CAAC;wBACnE,MAAM,SAAS,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;wBAE1C,IAAI,CAAC;4BACJ,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC;gCAC3C,MAAM,EAAE,MAAM;gCACd,GAAG,EAAE,GAAG,UAAU,4BAA4B;gCAC9C,OAAO,EAAE;oCACR,aAAa,EAAE,UAAU,WAAW,EAAE;oCACtC,cAAc,EAAE,kBAAkB;iCAClC;gCACD,IAAI,EAAE;oCACL,IAAI,EAAE,SAAS;oCACf,cAAc,EAAE,CAAC;oCACjB,WAAW,EAAE,CAAC;iCACd;gCACD,IAAI,EAAE,IAAI;gCACV,OAAO,EAAE,EAAE,GAAG,EAAE,GAAG,IAAI,EAAE,uBAAuB;6BAChD,CAAC,CAAC;4BAEH,gDAAgD;4BAChD,MAAM,OAAO,GAAI,QAAwB,CAAC,OAAwB,CAAC;4BACnE,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;gCACzC,MAAM,MAAM,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;gCAC1B,YAAY,CAAC,IAAI,CAAC;oCACjB,cAAc,EAAE,MAAA,MAAM,CAAC,cAAc,mCAAI,CAAC;oCAC1C,MAAM,EAAE,MAAA,MAAM,CAAC,MAAM,mCAAI,SAAS;oCAClC,OAAO,EAAE,MAAA,MAAM,CAAC,OAAO,mCAAI,KAAK;oCAChC,KAAK,EAAE,MAAM,CAAC,KAAK;oCACnB,GAAG,EAAE,MAAM,CAAC,GAAG;oCACf,cAAc,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK;iCAC9B,CAAC,CAAC;4BACJ,CAAC;wBACF,CAAC;wBAAC,OAAO,GAAG,EAAE,CAAC;4BACd,0DAA0D;4BAC1D,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;gCAC1B,YAAY,CAAC,IAAI,CAAC;oCACjB,cAAc,EAAE,CAAC;oCACjB,MAAM,EAAE,OAAO;oCACf,OAAO,EAAE,KAAK;oCACd,KAAK,EAAE,yBAA0B,GAAa,CAAC,OAAO,EAAE;oCACxD,GAAG,EAAE,IAAI,CAAC,GAAG;oCACb,cAAc,EAAE,IAAI,CAAC,KAAK;iCAC1B,CAAC,CAAC;4BACJ,CAAC;wBACF,CAAC;oBACF,CAAC;oBAED,8EAA8E;oBAC9E,MAAM,UAAU,GAAG,CAAC,GAAG,cAAc,EAAE,GAAG,YAAY,CAAC,CAAC;oBACxD,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAE,CAAC,CAAC,cAAyB,GAAI,CAAC,CAAC,cAAyB,CAAC,CAAC;oBAEvF,6DAA6D;oBAC7D,KAAK,MAAM,MAAM,IAAI,UAAU,EAAE,CAAC;wBACjC,MAAM,EAAE,cAAc,EAAE,CAAC,EAAE,GAAG,WAAW,EAAE,GAAG,MAAM,CAAC;wBACrD,UAAU,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;oBAC9B,CAAC;oBAED,uDAAuD;oBACvD,MAAM;gBACP,CAAC;gBAED,MAAM,IAAI,2BAAY,CAAC,IAAI,CAAC,OAAO,EAAE,EAAE;oBACtC,OAAO,EAAE,yBAAyB,QAAQ,mBAAmB,SAAS,GAAG;iBACzE,CAAC,CAAC;YACJ,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBAChB,MAAM,YAAY,GAAG,MAAC,KAAa,CAAC,OAAO,mCAAK,KAAe,CAAC,OAAO,CAAC;gBAExE,2DAA2D;gBAC3D,IAAK,KAAa,CAAC,UAAU,KAAK,GAAG,IAAK,KAAa,CAAC,UAAU,KAAK,GAAG,IAAI,YAAY,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,YAAY,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;oBAC5I,MAAM,IAAI,2BAAY,CAAC,IAAI,CAAC,OAAO,EAAE,EAAE;wBACtC,OAAO,EAAE,wHAAwH;qBACjI,CAAC,CAAC;gBACJ,CAAC;gBAED,IAAI,IAAI,CAAC,cAAc,EAAE,EAAE,CAAC;oBAC3B,UAAU,CAAC,IAAI,CAAC;wBACf,KAAK,EAAE,YAAY;wBACnB,SAAS;qBACT,CAAC,CAAC;oBACH,SAAS;gBACV,CAAC;gBACD,MAAM,KAAK,CAAC;YACb,CAAC;QACF,CAAC;QAED,OAAO,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;IACrD,CAAC;CACD;AAlkBD,0CAkkBC","file":"LinkedinScraper.node.js","sourcesContent":["/**\n * Author: Marco Visin\n * Date: 2025-12-22\n * LinkedIn Scraper n8n node\n * Interacts with the LinkedIn scraper microservice\n * Uses the same InNotes API credentials for authentication\n */\n\nimport {\n\tIDataObject,\n\tIExecuteFunctions,\n\tINodeExecutionData,\n\tINodeType,\n\tINodeTypeDescription,\n\tNodeApiError,\n} from 'n8n-workflow';\n\nfunction splitCommaSeparated(value: string): string[] {\n\treturn value\n\t\t.split(',')\n\t\t.map((entry) => entry.trim())\n\t\t.filter((entry) => entry.length > 0);\n}\n\nexport class LinkedinScraper implements INodeType {\n\tdescription: INodeTypeDescription = {\n\t\tdisplayName: 'LinkedIn Scraper Service',\n\t\tname: 'linkedinScraper',\n\t\tgroup: ['transform'],\n\t\tversion: 1,\n\t\tdescription: 'Interact with the LinkedIn scraper microservice',\n\t\tsubtitle: '={{$parameter[\"operation\"] + \": \" + $parameter[\"resource\"]}}',\n\t\ticon: 'file:logo.svg',\n\t\tdefaults: {\n\t\t\tname: 'LinkedIn Scraper',\n\t\t},\n\t\tinputs: ['main'],\n\t\toutputs: ['main'],\n\t\tcredentials: [\n\t\t\t{\n\t\t\t\t// Reuse the same InNotes API credentials\n\t\t\t\tname: 'inNotesApi',\n\t\t\t\trequired: true,\n\t\t\t},\n\t\t],\n\t\tproperties: [\n\t\t\t// Resource selection\n\t\t\t{\n\t\t\t\tdisplayName: 'Resource',\n\t\t\t\tname: 'resource',\n\t\t\t\ttype: 'options',\n\t\t\t\tnoDataExpression: true,\n\t\t\t\toptions: [\n\t\t\t\t\t{\n\t\t\t\t\t\tname: 'Jobs',\n\t\t\t\t\t\tvalue: 'jobs',\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tname: 'Job',\n\t\t\t\t\t\tvalue: 'job',\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tname: 'Company',\n\t\t\t\t\t\tvalue: 'company',\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t\tdefault: 'jobs',\n\t\t\t},\n\t\t\t// Jobs operations\n\t\t\t{\n\t\t\t\tdisplayName: 'Operation',\n\t\t\t\tname: 'operation',\n\t\t\t\ttype: 'options',\n\t\t\t\tdisplayOptions: {\n\t\t\t\t\tshow: {\n\t\t\t\t\t\tresource: ['jobs'],\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\toptions: [\n\t\t\t\t\t{\n\t\t\t\t\t\tname: 'Search',\n\t\t\t\t\t\tvalue: 'search',\n\t\t\t\t\t\taction: 'Search for jobs on LinkedIn and jobs.ch',\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t\tdefault: 'search',\n\t\t\t},\n\t\t\t// Job operations\n\t\t\t{\n\t\t\t\tdisplayName: 'Operation',\n\t\t\t\tname: 'operation',\n\t\t\t\ttype: 'options',\n\t\t\t\tdisplayOptions: {\n\t\t\t\t\tshow: {\n\t\t\t\t\t\tresource: ['job'],\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\toptions: [\n\t\t\t\t\t{\n\t\t\t\t\t\tname: 'Details',\n\t\t\t\t\t\tvalue: 'details',\n\t\t\t\t\t\taction: 'Fetch job details',\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t\tdefault: 'details',\n\t\t\t},\n\t\t\t// Company operations\n\t\t\t{\n\t\t\t\tdisplayName: 'Operation',\n\t\t\t\tname: 'operation',\n\t\t\t\ttype: 'options',\n\t\t\t\tdisplayOptions: {\n\t\t\t\t\tshow: {\n\t\t\t\t\t\tresource: ['company'],\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\toptions: [\n\t\t\t\t\t{\n\t\t\t\t\t\tname: 'Followers',\n\t\t\t\t\t\tvalue: 'followers',\n\t\t\t\t\t\taction: 'Fetch company follower count',\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t\tdefault: 'followers',\n\t\t\t},\n\t\t\t// Jobs search parameters\n\t\t\t{\n\t\t\t\tdisplayName: 'Job Titles',\n\t\t\t\tname: 'jobTitles',\n\t\t\t\ttype: 'string',\n\t\t\t\tdefault: '',\n\t\t\t\tplaceholder: 'Software Engineer, Developer',\n\t\t\t\tdescription: 'Comma-separated list of job titles to search for',\n\t\t\t\tdisplayOptions: {\n\t\t\t\t\tshow: {\n\t\t\t\t\t\tresource: ['jobs'],\n\t\t\t\t\t\toperation: ['search'],\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\trequired: true,\n\t\t\t},\n\t\t\t{\n\t\t\t\tdisplayName: 'Locations',\n\t\t\t\tname: 'locations',\n\t\t\t\ttype: 'string',\n\t\t\t\tdefault: '',\n\t\t\t\tplaceholder: 'Zurich, Remote',\n\t\t\t\tdescription: 'Comma-separated list of locations to search in',\n\t\t\t\tdisplayOptions: {\n\t\t\t\t\tshow: {\n\t\t\t\t\t\tresource: ['jobs'],\n\t\t\t\t\t\toperation: ['search'],\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\trequired: true,\n\t\t\t},\n\t\t\t{\n\t\t\t\tdisplayName: 'Max Results',\n\t\t\t\tname: 'maxResults',\n\t\t\t\ttype: 'number',\n\t\t\t\tdefault: 500,\n\t\t\t\ttypeOptions: {\n\t\t\t\t\tminValue: 1,\n\t\t\t\t\tmaxValue: 2000,\n\t\t\t\t},\n\t\t\t\tdisplayOptions: {\n\t\t\t\t\tshow: {\n\t\t\t\t\t\tresource: ['jobs'],\n\t\t\t\t\t\toperation: ['search'],\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tdisplayName: 'Include jobs.ch',\n\t\t\t\tname: 'includeJobsCh',\n\t\t\t\ttype: 'boolean',\n\t\t\t\tdefault: true,\n\t\t\t\tdisplayOptions: {\n\t\t\t\t\tshow: {\n\t\t\t\t\t\tresource: ['jobs'],\n\t\t\t\t\t\toperation: ['search'],\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tdisplayName: 'Time Range',\n\t\t\t\tname: 'timeRange',\n\t\t\t\ttype: 'options',\n\t\t\t\toptions: [\n\t\t\t\t\t{ name: 'Past 24 Hours', value: 'r86400' },\n\t\t\t\t\t{ name: 'Past Week', value: 'r604800' },\n\t\t\t\t\t{ name: 'Past Month', value: 'r2592000' },\n\t\t\t\t],\n\t\t\t\tdefault: 'r86400',\n\t\t\t\tdescription: 'Filter jobs by posting date',\n\t\t\t\tdisplayOptions: {\n\t\t\t\t\tshow: {\n\t\t\t\t\t\tresource: ['jobs'],\n\t\t\t\t\t\toperation: ['search'],\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tdisplayName: 'Company Blacklist',\n\t\t\t\tname: 'companyBlacklist',\n\t\t\t\ttype: 'string',\n\t\t\t\tdefault: '',\n\t\t\t\tplaceholder: 'Company A, Company B',\n\t\t\t\tdescription: 'Comma-separated list of companies to exclude',\n\t\t\t\tdisplayOptions: {\n\t\t\t\t\tshow: {\n\t\t\t\t\t\tresource: ['jobs'],\n\t\t\t\t\t\toperation: ['search'],\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tdisplayName: 'Keyword Blacklist',\n\t\t\t\tname: 'keywordBlacklist',\n\t\t\t\ttype: 'string',\n\t\t\t\tdefault: '',\n\t\t\t\tplaceholder: 'Senior, Lead',\n\t\t\t\tdescription: 'Comma-separated list of keywords to exclude from job titles',\n\t\t\t\tdisplayOptions: {\n\t\t\t\t\tshow: {\n\t\t\t\t\t\tresource: ['jobs'],\n\t\t\t\t\t\toperation: ['search'],\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\t// Job details parameters\n\t\t\t{\n\t\t\t\tdisplayName: 'Job URL',\n\t\t\t\tname: 'jobUrl',\n\t\t\t\ttype: 'string',\n\t\t\t\tdefault: '',\n\t\t\t\tdescription: 'LinkedIn or jobs.ch job URL',\n\t\t\t\tdisplayOptions: {\n\t\t\t\t\tshow: {\n\t\t\t\t\t\tresource: ['job'],\n\t\t\t\t\t\toperation: ['details'],\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\trequired: true,\n\t\t\t},\n\t\t\t// Company parameters\n\t\t\t{\n\t\t\t\tdisplayName: 'Company URL',\n\t\t\t\tname: 'companyUrl',\n\t\t\t\ttype: 'string',\n\t\t\t\tdefault: '',\n\t\t\t\tdescription: 'LinkedIn company URL',\n\t\t\t\tdisplayOptions: {\n\t\t\t\t\tshow: {\n\t\t\t\t\t\tresource: ['company'],\n\t\t\t\t\t\toperation: ['followers'],\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\trequired: true,\n\t\t\t},\n\t\t],\n\t};\n\n\tasync execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]> {\n\t\tconst items = this.getInputData();\n\t\tconst returnData: IDataObject[] = [];\n\n\t\t// Get InNotes API credentials (reused for scraper authentication)\n\t\tconst credentials = (await this.getCredentials('inNotesApi')) as IDataObject | null;\n\n\t\tif (!credentials) {\n\t\t\tthrow new NodeApiError(this.getNode(), {\n\t\t\t\tmessage: 'InNotes API credentials are missing',\n\t\t\t});\n\t\t}\n\n\t\t// Get the Bearer token from credentials\n\t\tconst authMethod = credentials.authMethod as string;\n\t\tlet bearerToken: string | undefined;\n\n\t\tif (authMethod === 'token') {\n\t\t\tbearerToken = credentials.token as string;\n\t\t} else {\n\t\t\tthrow new NodeApiError(this.getNode(), {\n\t\t\t\tmessage: 'LinkedIn Scraper requires Bearer token authentication. Please update your InNotes API credentials to use Bearer Token.',\n\t\t\t});\n\t\t}\n\n\t\tif (!bearerToken) {\n\t\t\tthrow new NodeApiError(this.getNode(), {\n\t\t\t\tmessage: 'Bearer token is missing from InNotes API credentials',\n\t\t\t});\n\t\t}\n\n\t\tfor (let itemIndex = 0; itemIndex < items.length; itemIndex++) {\n\t\t\tconst scraperUrl = 'https://scraper.innotes.me';\n\t\t\tconst resource = this.getNodeParameter('resource', itemIndex) as string;\n\t\t\tconst operation = this.getNodeParameter('operation', itemIndex) as string;\n\n\t\t\ttry {\n\t\t\t\tif (resource === 'jobs' && operation === 'search') {\n\t\t\t\t\tconst jobTitles = splitCommaSeparated(\n\t\t\t\t\t\tthis.getNodeParameter('jobTitles', itemIndex) as string,\n\t\t\t\t\t);\n\t\t\t\t\tconst locations = splitCommaSeparated(\n\t\t\t\t\t\tthis.getNodeParameter('locations', itemIndex) as string,\n\t\t\t\t\t);\n\t\t\t\t\tconst maxResults = this.getNodeParameter('maxResults', itemIndex) as number;\n\t\t\t\t\tconst includeJobsCh = this.getNodeParameter('includeJobsCh', itemIndex) as boolean;\n\t\t\t\t\tconst timeRange = this.getNodeParameter('timeRange', itemIndex) as string;\n\t\t\t\t\tconst companyBlacklist = splitCommaSeparated(\n\t\t\t\t\t\t(this.getNodeParameter('companyBlacklist', itemIndex) as string) || '',\n\t\t\t\t\t);\n\t\t\t\t\tconst keywordBlacklist = splitCommaSeparated(\n\t\t\t\t\t\t(this.getNodeParameter('keywordBlacklist', itemIndex) as string) || '',\n\t\t\t\t\t);\n\n\t\t\t\t\t// No cookies here, deliberately. This node used to read the\n\t\t\t\t\t// LinkedIn session from /api/user, parse three historical\n\t\t\t\t\t// shapes of it, and post it in the body below — putting a\n\t\t\t\t\t// live LinkedIn session through the workflow and into n8n's\n\t\t\t\t\t// execution log, for a component that has no use for it.\n\t\t\t\t\t//\n\t\t\t\t\t// The scraper already authenticates this same Bearer token\n\t\t\t\t\t// against InNotes on every request, so it fetches the\n\t\t\t\t\t// session itself. The cookies field is omitted entirely;\n\t\t\t\t\t// the scraper reads its absence as \"look it up\".\n\t\t\t\t\tconst requestBody: IDataObject = {\n\t\t\t\t\t\tjob_titles: jobTitles,\n\t\t\t\t\t\tlocations,\n\t\t\t\t\t\tmax_results: maxResults,\n\t\t\t\t\t\tinclude_jobs_ch: includeJobsCh,\n\t\t\t\t\t\ttime_range: timeRange,\n\t\t\t\t\t\tcompany_blacklist: companyBlacklist,\n\t\t\t\t\t\tkeywords_blacklist: keywordBlacklist,\n\t\t\t\t\t};\n\n\t\t\t\t\t// Search for jobs\n\t\t\t\t\tconst response = await this.helpers.request({\n\t\t\t\t\t\tmethod: 'POST',\n\t\t\t\t\t\turl: `${scraperUrl}/jobs/search`,\n\t\t\t\t\t\theaders: {\n\t\t\t\t\t\t\t'Authorization': `Bearer ${bearerToken}`,\n\t\t\t\t\t\t\t'Content-Type': 'application/json',\n\t\t\t\t\t\t},\n\t\t\t\t\t\tbody: requestBody,\n\t\t\t\t\t\tjson: true,\n\t\t\t\t\t\ttimeout: 90*60*1000,\n\t\t\t\t\t});\n\n\t\t\t\t\tconst jobs = (response as IDataObject).jobs as IDataObject[];\n\t\t\t\t\tif (!Array.isArray(jobs)) {\n\t\t\t\t\t\tthrow new NodeApiError(this.getNode(), {\n\t\t\t\t\t\t\tmessage: 'Unexpected response format from job search',\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\n\t\t\t\t\t// Deduplicate by link (used as ext_id in InNotes)\n\t\t\t\t\tconst seenLinks = new Set<string>();\n\t\t\t\t\tconst uniqueJobs: IDataObject[] = [];\n\t\t\t\t\tfor (const job of jobs) {\n\t\t\t\t\t\tconst link = (job.link as string) || '';\n\t\t\t\t\t\tif (link && seenLinks.has(link)) {\n\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (link) {\n\t\t\t\t\t\t\tseenLinks.add(link);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tuniqueJobs.push(job);\n\t\t\t\t\t}\n\t\t\t\t\tconst duplicatesRemoved = jobs.length - uniqueJobs.length;\n\t\t\t\t\tconsole.log(`Deduplicated: removed ${duplicatesRemoved} duplicates from ${jobs.length} results`);\n\t\t\t\t\treturnData.push(...uniqueJobs);\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tif (resource === 'job' && operation === 'details') {\n\t\t\t\t// Batch processing: collect all URLs, chunk them, and send batch requests\n\t\t\t\t\tconst CHUNK_SIZE = 30;\n\n\t\t\t\t\t// Only process on first item - we'll handle all items at once\n\t\t\t\t\tif (itemIndex > 0) {\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\n\t\t\t\t// Collect all job URLs with their original indices\n\t\t\t\tinterface UrlWithIndex {\n\t\t\t\t\turl: string;\n\t\t\t\t\tindex: number;\n\t\t\t\t}\n\t\t\t\tconst validUrls: UrlWithIndex[] = [];\n\t\t\t\tconst invalidResults: IDataObject[] = [];\n\n\t\t\t\t// Validate and categorize all URLs\n\t\t\t\tfor (let i = 0; i < items.length; i++) {\n\t\t\t\t\tconst jobUrl = this.getNodeParameter('jobUrl', i) as string;\n\n\t\t\t\t\tif (jobUrl?.startsWith('http')) {\n\t\t\t\t\t\tvalidUrls.push({ url: jobUrl, index: i });\n\t\t\t\t\t} else {\n\t\t\t\t\t\t// Invalid URL - add to results immediately\n\t\t\t\t\t\tinvalidResults.push({\n\t\t\t\t\t\t\tsuccess: false,\n\t\t\t\t\t\t\terror: `Invalid job URL: ${jobUrl || 'empty'}`,\n\t\t\t\t\t\t\t_originalIndex: i,\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Process valid URLs in chunks\n\t\t\t\tconst batchResults: IDataObject[] = [];\n\n\t\t\t\tfor (let chunkStart = 0; chunkStart < validUrls.length; chunkStart += CHUNK_SIZE) {\n\t\t\t\t\tconst chunk = validUrls.slice(chunkStart, chunkStart + CHUNK_SIZE);\n\t\t\t\t\tconst chunkUrls = chunk.map((c) => c.url);\n\n\t\t\t\t\ttry {\n\t\t\t\t\t\tconst response = await this.helpers.request({\n\t\t\t\t\t\t\tmethod: 'POST',\n\t\t\t\t\t\t\turl: `${scraperUrl}/jobs/details/batch`,\n\t\t\t\t\t\t\theaders: {\n\t\t\t\t\t\t\t\tAuthorization: `Bearer ${bearerToken}`,\n\t\t\t\t\t\t\t\t'Content-Type': 'application/json',\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tbody: {\n\t\t\t\t\t\t\t\turls: chunkUrls,\n\t\t\t\t\t\t\t\tmax_concurrent: 5,\n\t\t\t\t\t\t\t\tmax_retries: 7,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tjson: true,\n\t\t\t\t\t\t\ttimeout: 15 * 60 * 1000, // 15 minutes per batch (more retries = longer)\n\t\t\t\t\t\t});\n\n\t\t\t\t\t\t// Map results back, preserving original indices\n\t\t\t\t\t\tconst results = (response as IDataObject).results as IDataObject[];\n\t\t\t\t\t\tfor (let j = 0; j < results.length; j++) {\n\t\t\t\t\t\t\tconst result = results[j];\n\t\t\t\t\t\t\tbatchResults.push({\n\t\t\t\t\t\t\t\t...result,\n\t\t\t\t\t\t\t\t_originalIndex: chunk[j].index,\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t}\n\t\t\t\t\t} catch (err) {\n\t\t\t\t\t\t// Re-throw auth errors (session expired)\n\t\t\t\t\t\tconst statusCode = (err as any).statusCode;\n\t\t\t\t\t\tconst errMsg = (err as Error).message || '';\n\t\t\t\t\t\tif (statusCode === 401 || statusCode === 403 || errMsg.includes('401') || errMsg.includes('403')) {\n\t\t\t\t\t\t\tthrow err;\n\t\t\t\t\t\t}\n\t\t\t\t\t\t// If entire batch fails, mark all URLs in chunk as failed\n\t\t\t\t\t\tfor (const item of chunk) {\n\t\t\t\t\t\t\tbatchResults.push({\n\t\t\t\t\t\t\t\tsuccess: false,\n\t\t\t\t\t\t\t\terror: `Batch request failed: ${(err as Error).message}`,\n\t\t\t\t\t\t\t\turl: item.url,\n\t\t\t\t\t\t\t\t_originalIndex: item.index,\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Combine invalid and batch results, sort by original index to maintain order\n\t\t\t\tconst allResults = [...invalidResults, ...batchResults];\n\t\t\t\tallResults.sort((a, b) => (a._originalIndex as number) - (b._originalIndex as number));\n\n\t\t\t\t// Remove internal _originalIndex field and add to returnData\n\t\t\t\tfor (const result of allResults) {\n\t\t\t\t\tconst { _originalIndex: _, ...cleanResult } = result;\n\t\t\t\t\treturnData.push(cleanResult);\n\t\t\t\t}\n\n\t\t\t\t// Skip further iterations since we processed all items\n\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tif (resource === 'company' && operation === 'followers') {\n\t\t\t\t// Batch processing: collect all URLs, chunk them, and send batch requests\n\t\t\t\t\tconst CHUNK_SIZE = 30;\n\n\t\t\t\t\t// Only process on first item - we'll handle all items at once\n\t\t\t\t\tif (itemIndex > 0) {\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\n\t\t\t\t\t// Collect all company URLs with their original indices\n\t\t\t\t\tinterface UrlWithIndex {\n\t\t\t\t\t\turl: string;\n\t\t\t\t\t\tindex: number;\n\t\t\t\t\t}\n\t\t\t\t\tconst validUrls: UrlWithIndex[] = [];\n\t\t\t\t\tconst invalidResults: IDataObject[] = [];\n\n\t\t\t\t\t// Validate and categorize all URLs\n\t\t\t\t\tfor (let i = 0; i < items.length; i++) {\n\t\t\t\t\t\tconst companyUrl = this.getNodeParameter('companyUrl', i) as string;\n\n\t\t\t\t\t\tif (companyUrl?.startsWith('http')) {\n\t\t\t\t\t\t\tvalidUrls.push({ url: companyUrl, index: i });\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t// Invalid URL - add to results immediately\n\t\t\t\t\t\t\tinvalidResults.push({\n\t\t\t\t\t\t\t\tfollower_count: 0,\n\t\t\t\t\t\t\t\tsource: 'skipped',\n\t\t\t\t\t\t\t\tsuccess: false,\n\t\t\t\t\t\t\t\terror: `Invalid company URL: ${companyUrl || 'empty'}`,\n\t\t\t\t\t\t\t\t_originalIndex: i,\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\t// Process valid URLs in chunks\n\t\t\t\t\tconst batchResults: IDataObject[] = [];\n\n\t\t\t\t\tfor (let chunkStart = 0; chunkStart < validUrls.length; chunkStart += CHUNK_SIZE) {\n\t\t\t\t\t\tconst chunk = validUrls.slice(chunkStart, chunkStart + CHUNK_SIZE);\n\t\t\t\t\t\tconst chunkUrls = chunk.map((c) => c.url);\n\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tconst response = await this.helpers.request({\n\t\t\t\t\t\t\t\tmethod: 'POST',\n\t\t\t\t\t\t\t\turl: `${scraperUrl}/companies/followers/batch`,\n\t\t\t\t\t\t\t\theaders: {\n\t\t\t\t\t\t\t\t\tAuthorization: `Bearer ${bearerToken}`,\n\t\t\t\t\t\t\t\t\t'Content-Type': 'application/json',\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\tbody: {\n\t\t\t\t\t\t\t\t\turls: chunkUrls,\n\t\t\t\t\t\t\t\t\tmax_concurrent: 5,\n\t\t\t\t\t\t\t\t\tmax_retries: 7,\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\tjson: true,\n\t\t\t\t\t\t\t\ttimeout: 10 * 60 * 1000, // 10 minutes per batch\n\t\t\t\t\t\t\t});\n\n\t\t\t\t\t\t\t// Map results back, preserving original indices\n\t\t\t\t\t\t\tconst results = (response as IDataObject).results as IDataObject[];\n\t\t\t\t\t\t\tfor (let j = 0; j < results.length; j++) {\n\t\t\t\t\t\t\t\tconst result = results[j];\n\t\t\t\t\t\t\t\tbatchResults.push({\n\t\t\t\t\t\t\t\t\tfollower_count: result.follower_count ?? 0,\n\t\t\t\t\t\t\t\t\tsource: result.source ?? 'unknown',\n\t\t\t\t\t\t\t\t\tsuccess: result.success ?? false,\n\t\t\t\t\t\t\t\t\terror: result.error,\n\t\t\t\t\t\t\t\t\turl: result.url,\n\t\t\t\t\t\t\t\t\t_originalIndex: chunk[j].index,\n\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} catch (err) {\n\t\t\t\t\t\t\t// If entire batch fails, mark all URLs in chunk as failed\n\t\t\t\t\t\t\tfor (const item of chunk) {\n\t\t\t\t\t\t\t\tbatchResults.push({\n\t\t\t\t\t\t\t\t\tfollower_count: 0,\n\t\t\t\t\t\t\t\t\tsource: 'error',\n\t\t\t\t\t\t\t\t\tsuccess: false,\n\t\t\t\t\t\t\t\t\terror: `Batch request failed: ${(err as Error).message}`,\n\t\t\t\t\t\t\t\t\turl: item.url,\n\t\t\t\t\t\t\t\t\t_originalIndex: item.index,\n\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\t// Combine invalid and batch results, sort by original index to maintain order\n\t\t\t\t\tconst allResults = [...invalidResults, ...batchResults];\n\t\t\t\t\tallResults.sort((a, b) => (a._originalIndex as number) - (b._originalIndex as number));\n\n\t\t\t\t\t// Remove internal _originalIndex field and add to returnData\n\t\t\t\t\tfor (const result of allResults) {\n\t\t\t\t\t\tconst { _originalIndex: _, ...cleanResult } = result;\n\t\t\t\t\t\treturnData.push(cleanResult);\n\t\t\t\t\t}\n\n\t\t\t\t\t// Skip further iterations since we processed all items\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tthrow new NodeApiError(this.getNode(), {\n\t\t\t\t\tmessage: `Unsupported resource (${resource}) or operation (${operation})`,\n\t\t\t\t});\n\t\t\t} catch (error) {\n\t\t\t\tconst errorMessage = (error as any).message ?? (error as Error).message;\n\n\t\t\t\t// Check for authentication errors from the scraper service\n\t\t\t\tif ((error as any).statusCode === 401 || (error as any).statusCode === 403 || errorMessage.includes('401') || errorMessage.includes('403')) {\n\t\t\t\t\tthrow new NodeApiError(this.getNode(), {\n\t\t\t\t\t\tmessage: 'LinkedIn session expired. Please visit LinkedIn in a browser with the InNotes extension enabled to renew your session.',\n\t\t\t\t\t});\n\t\t\t\t}\n\n\t\t\t\tif (this.continueOnFail()) {\n\t\t\t\t\treturnData.push({\n\t\t\t\t\t\terror: errorMessage,\n\t\t\t\t\t\titemIndex,\n\t\t\t\t\t});\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t}\n\n\t\treturn [returnData.map((data) => ({ json: data }))];\n\t}\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../nodes/LinkedinScraper/LinkedinScraper.node.ts"],"names":[],"mappings":"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","file":"LinkedinScraper.node.js","sourcesContent":["/**\n * Author: Marco Visin\n * Date: 2025-12-22\n * LinkedIn Scraper n8n node\n * Interacts with the LinkedIn scraper microservice\n * Uses the same InNotes API credentials for authentication\n */\n\nimport {\n\tIDataObject,\n\tIExecuteFunctions,\n\tINodeExecutionData,\n\tINodeType,\n\tINodeTypeDescription,\n\tNodeApiError,\n} from 'n8n-workflow';\n\nfunction splitCommaSeparated(value: string): string[] {\n\treturn value\n\t\t.split(',')\n\t\t.map((entry) => entry.trim())\n\t\t.filter((entry) => entry.length > 0);\n}\n\nexport class LinkedinScraper implements INodeType {\n\tdescription: INodeTypeDescription = {\n\t\tdisplayName: 'LinkedIn Scraper Service',\n\t\tname: 'linkedinScraper',\n\t\tgroup: ['transform'],\n\t\tversion: 1,\n\t\tdescription: 'Interact with the LinkedIn scraper microservice',\n\t\tsubtitle: '={{$parameter[\"operation\"] + \": \" + $parameter[\"resource\"]}}',\n\t\ticon: 'file:logo.svg',\n\t\tdefaults: {\n\t\t\tname: 'LinkedIn Scraper',\n\t\t},\n\t\tinputs: ['main'],\n\t\toutputs: ['main'],\n\t\tcredentials: [\n\t\t\t{\n\t\t\t\t// Reuse the same InNotes API credentials\n\t\t\t\tname: 'inNotesApi',\n\t\t\t\trequired: true,\n\t\t\t},\n\t\t],\n\t\tproperties: [\n\t\t\t// Resource selection\n\t\t\t{\n\t\t\t\tdisplayName: 'Resource',\n\t\t\t\tname: 'resource',\n\t\t\t\ttype: 'options',\n\t\t\t\tnoDataExpression: true,\n\t\t\t\toptions: [\n\t\t\t\t\t{\n\t\t\t\t\t\tname: 'Jobs',\n\t\t\t\t\t\tvalue: 'jobs',\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tname: 'Job',\n\t\t\t\t\t\tvalue: 'job',\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tname: 'Company',\n\t\t\t\t\t\tvalue: 'company',\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t\tdefault: 'jobs',\n\t\t\t},\n\t\t\t// Jobs operations\n\t\t\t{\n\t\t\t\tdisplayName: 'Operation',\n\t\t\t\tname: 'operation',\n\t\t\t\ttype: 'options',\n\t\t\t\tdisplayOptions: {\n\t\t\t\t\tshow: {\n\t\t\t\t\t\tresource: ['jobs'],\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\toptions: [\n\t\t\t\t\t{\n\t\t\t\t\t\tname: 'Search',\n\t\t\t\t\t\tvalue: 'search',\n\t\t\t\t\t\taction: 'Search for jobs on LinkedIn and jobs.ch',\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t\tdefault: 'search',\n\t\t\t},\n\t\t\t// Job operations\n\t\t\t{\n\t\t\t\tdisplayName: 'Operation',\n\t\t\t\tname: 'operation',\n\t\t\t\ttype: 'options',\n\t\t\t\tdisplayOptions: {\n\t\t\t\t\tshow: {\n\t\t\t\t\t\tresource: ['job'],\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\toptions: [\n\t\t\t\t\t{\n\t\t\t\t\t\tname: 'Details',\n\t\t\t\t\t\tvalue: 'details',\n\t\t\t\t\t\taction: 'Fetch job details',\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t\tdefault: 'details',\n\t\t\t},\n\t\t\t// Company operations\n\t\t\t{\n\t\t\t\tdisplayName: 'Operation',\n\t\t\t\tname: 'operation',\n\t\t\t\ttype: 'options',\n\t\t\t\tdisplayOptions: {\n\t\t\t\t\tshow: {\n\t\t\t\t\t\tresource: ['company'],\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\toptions: [\n\t\t\t\t\t{\n\t\t\t\t\t\tname: 'Followers',\n\t\t\t\t\t\tvalue: 'followers',\n\t\t\t\t\t\taction: 'Fetch company follower count',\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t\tdefault: 'followers',\n\t\t\t},\n\t\t\t// Jobs search parameters\n\t\t\t{\n\t\t\t\tdisplayName: 'Job Titles',\n\t\t\t\tname: 'jobTitles',\n\t\t\t\ttype: 'string',\n\t\t\t\tdefault: '',\n\t\t\t\tplaceholder: 'Software Engineer, Developer',\n\t\t\t\tdescription: 'Comma-separated list of job titles to search for',\n\t\t\t\tdisplayOptions: {\n\t\t\t\t\tshow: {\n\t\t\t\t\t\tresource: ['jobs'],\n\t\t\t\t\t\toperation: ['search'],\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\trequired: true,\n\t\t\t},\n\t\t\t{\n\t\t\t\tdisplayName: 'Locations',\n\t\t\t\tname: 'locations',\n\t\t\t\ttype: 'string',\n\t\t\t\tdefault: '',\n\t\t\t\tplaceholder: 'Zurich, Remote',\n\t\t\t\tdescription: 'Comma-separated list of locations to search in',\n\t\t\t\tdisplayOptions: {\n\t\t\t\t\tshow: {\n\t\t\t\t\t\tresource: ['jobs'],\n\t\t\t\t\t\toperation: ['search'],\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\trequired: true,\n\t\t\t},\n\t\t\t{\n\t\t\t\tdisplayName: 'Max Results',\n\t\t\t\tname: 'maxResults',\n\t\t\t\ttype: 'number',\n\t\t\t\tdefault: 500,\n\t\t\t\ttypeOptions: {\n\t\t\t\t\tminValue: 1,\n\t\t\t\t\tmaxValue: 2000,\n\t\t\t\t},\n\t\t\t\tdisplayOptions: {\n\t\t\t\t\tshow: {\n\t\t\t\t\t\tresource: ['jobs'],\n\t\t\t\t\t\toperation: ['search'],\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tdisplayName: 'Include jobs.ch',\n\t\t\t\tname: 'includeJobsCh',\n\t\t\t\ttype: 'boolean',\n\t\t\t\tdefault: true,\n\t\t\t\tdisplayOptions: {\n\t\t\t\t\tshow: {\n\t\t\t\t\t\tresource: ['jobs'],\n\t\t\t\t\t\toperation: ['search'],\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tdisplayName: 'Time Range',\n\t\t\t\tname: 'timeRange',\n\t\t\t\ttype: 'options',\n\t\t\t\toptions: [\n\t\t\t\t\t{ name: 'Past 24 Hours', value: 'r86400' },\n\t\t\t\t\t{ name: 'Past Week', value: 'r604800' },\n\t\t\t\t\t{ name: 'Past Month', value: 'r2592000' },\n\t\t\t\t],\n\t\t\t\tdefault: 'r86400',\n\t\t\t\tdescription: 'Filter jobs by posting date',\n\t\t\t\tdisplayOptions: {\n\t\t\t\t\tshow: {\n\t\t\t\t\t\tresource: ['jobs'],\n\t\t\t\t\t\toperation: ['search'],\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tdisplayName: 'Company Blacklist',\n\t\t\t\tname: 'companyBlacklist',\n\t\t\t\ttype: 'string',\n\t\t\t\tdefault: '',\n\t\t\t\tplaceholder: 'Company A, Company B',\n\t\t\t\tdescription: 'Comma-separated list of companies to exclude',\n\t\t\t\tdisplayOptions: {\n\t\t\t\t\tshow: {\n\t\t\t\t\t\tresource: ['jobs'],\n\t\t\t\t\t\toperation: ['search'],\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tdisplayName: 'Keyword Blacklist',\n\t\t\t\tname: 'keywordBlacklist',\n\t\t\t\ttype: 'string',\n\t\t\t\tdefault: '',\n\t\t\t\tplaceholder: 'Senior, Lead',\n\t\t\t\tdescription: 'Comma-separated list of keywords to exclude from job titles',\n\t\t\t\tdisplayOptions: {\n\t\t\t\t\tshow: {\n\t\t\t\t\t\tresource: ['jobs'],\n\t\t\t\t\t\toperation: ['search'],\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\t// Job details parameters\n\t\t\t{\n\t\t\t\tdisplayName: 'Job URL',\n\t\t\t\tname: 'jobUrl',\n\t\t\t\ttype: 'string',\n\t\t\t\tdefault: '',\n\t\t\t\tdescription: 'LinkedIn or jobs.ch job URL',\n\t\t\t\tdisplayOptions: {\n\t\t\t\t\tshow: {\n\t\t\t\t\t\tresource: ['job'],\n\t\t\t\t\t\toperation: ['details'],\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\trequired: true,\n\t\t\t},\n\t\t\t// Company parameters\n\t\t\t{\n\t\t\t\tdisplayName: 'Company URL',\n\t\t\t\tname: 'companyUrl',\n\t\t\t\ttype: 'string',\n\t\t\t\tdefault: '',\n\t\t\t\tdescription: 'LinkedIn company URL',\n\t\t\t\tdisplayOptions: {\n\t\t\t\t\tshow: {\n\t\t\t\t\t\tresource: ['company'],\n\t\t\t\t\t\toperation: ['followers'],\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\trequired: true,\n\t\t\t},\n\t\t],\n\t};\n\n\tasync execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]> {\n\t\tconst items = this.getInputData();\n\t\tconst returnData: IDataObject[] = [];\n\n\t\t// Get InNotes API credentials (reused for scraper authentication)\n\t\tconst credentials = (await this.getCredentials('inNotesApi')) as IDataObject | null;\n\n\t\tif (!credentials) {\n\t\t\tthrow new NodeApiError(this.getNode(), {\n\t\t\t\tmessage: 'InNotes API credentials are missing',\n\t\t\t});\n\t\t}\n\n\t\t// No authMethod check here, deliberately. The InNotes credential used to\n\t\t// offer a choice between a Bearer token and username/password, and this\n\t\t// node refused anything that was not 'token'. 3b8c1e46 deleted the\n\t\t// username/password auth and the authMethod field along with it — but\n\t\t// only from the credential, in n8n_node/. This file was never touched,\n\t\t// so the guard went on reading a property that no longer exists and no\n\t\t// longer can: the field is gone from the credential type, so nothing\n\t\t// writes it and the n8n UI has no way to set it.\n\t\t//\n\t\t// The failure was total for any credential that did not happen to carry\n\t\t// the value left over from before, and the message sent people to go and\n\t\t// select an option that is no longer on the screen. The only thing this\n\t\t// node actually needs is the token.\n\t\t// Author: Marco — 2026-08-05\n\t\tconst bearerToken = credentials.token as string | undefined;\n\n\t\tif (!bearerToken) {\n\t\t\tthrow new NodeApiError(this.getNode(), {\n\t\t\t\tmessage: 'Bearer token is missing from InNotes API credentials',\n\t\t\t});\n\t\t}\n\n\t\tfor (let itemIndex = 0; itemIndex < items.length; itemIndex++) {\n\t\t\tconst scraperUrl = 'https://scraper.innotes.me';\n\t\t\tconst resource = this.getNodeParameter('resource', itemIndex) as string;\n\t\t\tconst operation = this.getNodeParameter('operation', itemIndex) as string;\n\n\t\t\ttry {\n\t\t\t\tif (resource === 'jobs' && operation === 'search') {\n\t\t\t\t\tconst jobTitles = splitCommaSeparated(\n\t\t\t\t\t\tthis.getNodeParameter('jobTitles', itemIndex) as string,\n\t\t\t\t\t);\n\t\t\t\t\tconst locations = splitCommaSeparated(\n\t\t\t\t\t\tthis.getNodeParameter('locations', itemIndex) as string,\n\t\t\t\t\t);\n\t\t\t\t\tconst maxResults = this.getNodeParameter('maxResults', itemIndex) as number;\n\t\t\t\t\tconst includeJobsCh = this.getNodeParameter('includeJobsCh', itemIndex) as boolean;\n\t\t\t\t\tconst timeRange = this.getNodeParameter('timeRange', itemIndex) as string;\n\t\t\t\t\tconst companyBlacklist = splitCommaSeparated(\n\t\t\t\t\t\t(this.getNodeParameter('companyBlacklist', itemIndex) as string) || '',\n\t\t\t\t\t);\n\t\t\t\t\tconst keywordBlacklist = splitCommaSeparated(\n\t\t\t\t\t\t(this.getNodeParameter('keywordBlacklist', itemIndex) as string) || '',\n\t\t\t\t\t);\n\n\t\t\t\t\t// No cookies here, deliberately. This node used to read the\n\t\t\t\t\t// LinkedIn session from /api/user, parse three historical\n\t\t\t\t\t// shapes of it, and post it in the body below — putting a\n\t\t\t\t\t// live LinkedIn session through the workflow and into n8n's\n\t\t\t\t\t// execution log, for a component that has no use for it.\n\t\t\t\t\t//\n\t\t\t\t\t// The scraper already authenticates this same Bearer token\n\t\t\t\t\t// against InNotes on every request, so it fetches the\n\t\t\t\t\t// session itself. The cookies field is omitted entirely;\n\t\t\t\t\t// the scraper reads its absence as \"look it up\".\n\t\t\t\t\tconst requestBody: IDataObject = {\n\t\t\t\t\t\tjob_titles: jobTitles,\n\t\t\t\t\t\tlocations,\n\t\t\t\t\t\tmax_results: maxResults,\n\t\t\t\t\t\tinclude_jobs_ch: includeJobsCh,\n\t\t\t\t\t\ttime_range: timeRange,\n\t\t\t\t\t\tcompany_blacklist: companyBlacklist,\n\t\t\t\t\t\tkeywords_blacklist: keywordBlacklist,\n\t\t\t\t\t};\n\n\t\t\t\t\t// Search for jobs\n\t\t\t\t\tconst response = await this.helpers.request({\n\t\t\t\t\t\tmethod: 'POST',\n\t\t\t\t\t\turl: `${scraperUrl}/jobs/search`,\n\t\t\t\t\t\theaders: {\n\t\t\t\t\t\t\t'Authorization': `Bearer ${bearerToken}`,\n\t\t\t\t\t\t\t'Content-Type': 'application/json',\n\t\t\t\t\t\t},\n\t\t\t\t\t\tbody: requestBody,\n\t\t\t\t\t\tjson: true,\n\t\t\t\t\t\ttimeout: 90*60*1000,\n\t\t\t\t\t});\n\n\t\t\t\t\tconst jobs = (response as IDataObject).jobs as IDataObject[];\n\t\t\t\t\tif (!Array.isArray(jobs)) {\n\t\t\t\t\t\tthrow new NodeApiError(this.getNode(), {\n\t\t\t\t\t\t\tmessage: 'Unexpected response format from job search',\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\n\t\t\t\t\t// Deduplicate by link (used as ext_id in InNotes)\n\t\t\t\t\tconst seenLinks = new Set<string>();\n\t\t\t\t\tconst uniqueJobs: IDataObject[] = [];\n\t\t\t\t\tfor (const job of jobs) {\n\t\t\t\t\t\tconst link = (job.link as string) || '';\n\t\t\t\t\t\tif (link && seenLinks.has(link)) {\n\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (link) {\n\t\t\t\t\t\t\tseenLinks.add(link);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tuniqueJobs.push(job);\n\t\t\t\t\t}\n\t\t\t\t\tconst duplicatesRemoved = jobs.length - uniqueJobs.length;\n\t\t\t\t\tconsole.log(`Deduplicated: removed ${duplicatesRemoved} duplicates from ${jobs.length} results`);\n\t\t\t\t\treturnData.push(...uniqueJobs);\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tif (resource === 'job' && operation === 'details') {\n\t\t\t\t// Batch processing: collect all URLs, chunk them, and send batch requests\n\t\t\t\t\tconst CHUNK_SIZE = 30;\n\n\t\t\t\t\t// Only process on first item - we'll handle all items at once\n\t\t\t\t\tif (itemIndex > 0) {\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\n\t\t\t\t// Collect all job URLs with their original indices\n\t\t\t\tinterface UrlWithIndex {\n\t\t\t\t\turl: string;\n\t\t\t\t\tindex: number;\n\t\t\t\t}\n\t\t\t\tconst validUrls: UrlWithIndex[] = [];\n\t\t\t\tconst invalidResults: IDataObject[] = [];\n\n\t\t\t\t// Validate and categorize all URLs\n\t\t\t\tfor (let i = 0; i < items.length; i++) {\n\t\t\t\t\tconst jobUrl = this.getNodeParameter('jobUrl', i) as string;\n\n\t\t\t\t\tif (jobUrl?.startsWith('http')) {\n\t\t\t\t\t\tvalidUrls.push({ url: jobUrl, index: i });\n\t\t\t\t\t} else {\n\t\t\t\t\t\t// Invalid URL - add to results immediately\n\t\t\t\t\t\tinvalidResults.push({\n\t\t\t\t\t\t\tsuccess: false,\n\t\t\t\t\t\t\terror: `Invalid job URL: ${jobUrl || 'empty'}`,\n\t\t\t\t\t\t\t_originalIndex: i,\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Process valid URLs in chunks\n\t\t\t\tconst batchResults: IDataObject[] = [];\n\n\t\t\t\tfor (let chunkStart = 0; chunkStart < validUrls.length; chunkStart += CHUNK_SIZE) {\n\t\t\t\t\tconst chunk = validUrls.slice(chunkStart, chunkStart + CHUNK_SIZE);\n\t\t\t\t\tconst chunkUrls = chunk.map((c) => c.url);\n\n\t\t\t\t\ttry {\n\t\t\t\t\t\tconst response = await this.helpers.request({\n\t\t\t\t\t\t\tmethod: 'POST',\n\t\t\t\t\t\t\turl: `${scraperUrl}/jobs/details/batch`,\n\t\t\t\t\t\t\theaders: {\n\t\t\t\t\t\t\t\tAuthorization: `Bearer ${bearerToken}`,\n\t\t\t\t\t\t\t\t'Content-Type': 'application/json',\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tbody: {\n\t\t\t\t\t\t\t\turls: chunkUrls,\n\t\t\t\t\t\t\t\tmax_concurrent: 5,\n\t\t\t\t\t\t\t\tmax_retries: 7,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tjson: true,\n\t\t\t\t\t\t\ttimeout: 15 * 60 * 1000, // 15 minutes per batch (more retries = longer)\n\t\t\t\t\t\t});\n\n\t\t\t\t\t\t// Map results back, preserving original indices\n\t\t\t\t\t\tconst results = (response as IDataObject).results as IDataObject[];\n\t\t\t\t\t\tfor (let j = 0; j < results.length; j++) {\n\t\t\t\t\t\t\tconst result = results[j];\n\t\t\t\t\t\t\tbatchResults.push({\n\t\t\t\t\t\t\t\t...result,\n\t\t\t\t\t\t\t\t_originalIndex: chunk[j].index,\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t}\n\t\t\t\t\t} catch (err) {\n\t\t\t\t\t\t// Re-throw auth errors (session expired)\n\t\t\t\t\t\tconst statusCode = (err as any).statusCode;\n\t\t\t\t\t\tconst errMsg = (err as Error).message || '';\n\t\t\t\t\t\tif (statusCode === 401 || statusCode === 403 || errMsg.includes('401') || errMsg.includes('403')) {\n\t\t\t\t\t\t\tthrow err;\n\t\t\t\t\t\t}\n\t\t\t\t\t\t// If entire batch fails, mark all URLs in chunk as failed\n\t\t\t\t\t\tfor (const item of chunk) {\n\t\t\t\t\t\t\tbatchResults.push({\n\t\t\t\t\t\t\t\tsuccess: false,\n\t\t\t\t\t\t\t\terror: `Batch request failed: ${(err as Error).message}`,\n\t\t\t\t\t\t\t\turl: item.url,\n\t\t\t\t\t\t\t\t_originalIndex: item.index,\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Combine invalid and batch results, sort by original index to maintain order\n\t\t\t\tconst allResults = [...invalidResults, ...batchResults];\n\t\t\t\tallResults.sort((a, b) => (a._originalIndex as number) - (b._originalIndex as number));\n\n\t\t\t\t// Remove internal _originalIndex field and add to returnData\n\t\t\t\tfor (const result of allResults) {\n\t\t\t\t\tconst { _originalIndex: _, ...cleanResult } = result;\n\t\t\t\t\treturnData.push(cleanResult);\n\t\t\t\t}\n\n\t\t\t\t// Skip further iterations since we processed all items\n\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tif (resource === 'company' && operation === 'followers') {\n\t\t\t\t// Batch processing: collect all URLs, chunk them, and send batch requests\n\t\t\t\t\tconst CHUNK_SIZE = 30;\n\n\t\t\t\t\t// Only process on first item - we'll handle all items at once\n\t\t\t\t\tif (itemIndex > 0) {\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\n\t\t\t\t\t// Collect all company URLs with their original indices\n\t\t\t\t\tinterface UrlWithIndex {\n\t\t\t\t\t\turl: string;\n\t\t\t\t\t\tindex: number;\n\t\t\t\t\t}\n\t\t\t\t\tconst validUrls: UrlWithIndex[] = [];\n\t\t\t\t\tconst invalidResults: IDataObject[] = [];\n\n\t\t\t\t\t// Validate and categorize all URLs\n\t\t\t\t\tfor (let i = 0; i < items.length; i++) {\n\t\t\t\t\t\tconst companyUrl = this.getNodeParameter('companyUrl', i) as string;\n\n\t\t\t\t\t\tif (companyUrl?.startsWith('http')) {\n\t\t\t\t\t\t\tvalidUrls.push({ url: companyUrl, index: i });\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t// Invalid URL - add to results immediately\n\t\t\t\t\t\t\tinvalidResults.push({\n\t\t\t\t\t\t\t\tfollower_count: 0,\n\t\t\t\t\t\t\t\tsource: 'skipped',\n\t\t\t\t\t\t\t\tsuccess: false,\n\t\t\t\t\t\t\t\terror: `Invalid company URL: ${companyUrl || 'empty'}`,\n\t\t\t\t\t\t\t\t_originalIndex: i,\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\t// Process valid URLs in chunks\n\t\t\t\t\tconst batchResults: IDataObject[] = [];\n\n\t\t\t\t\tfor (let chunkStart = 0; chunkStart < validUrls.length; chunkStart += CHUNK_SIZE) {\n\t\t\t\t\t\tconst chunk = validUrls.slice(chunkStart, chunkStart + CHUNK_SIZE);\n\t\t\t\t\t\tconst chunkUrls = chunk.map((c) => c.url);\n\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tconst response = await this.helpers.request({\n\t\t\t\t\t\t\t\tmethod: 'POST',\n\t\t\t\t\t\t\t\turl: `${scraperUrl}/companies/followers/batch`,\n\t\t\t\t\t\t\t\theaders: {\n\t\t\t\t\t\t\t\t\tAuthorization: `Bearer ${bearerToken}`,\n\t\t\t\t\t\t\t\t\t'Content-Type': 'application/json',\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\tbody: {\n\t\t\t\t\t\t\t\t\turls: chunkUrls,\n\t\t\t\t\t\t\t\t\tmax_concurrent: 5,\n\t\t\t\t\t\t\t\t\tmax_retries: 7,\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\tjson: true,\n\t\t\t\t\t\t\t\ttimeout: 10 * 60 * 1000, // 10 minutes per batch\n\t\t\t\t\t\t\t});\n\n\t\t\t\t\t\t\t// Map results back, preserving original indices\n\t\t\t\t\t\t\tconst results = (response as IDataObject).results as IDataObject[];\n\t\t\t\t\t\t\tfor (let j = 0; j < results.length; j++) {\n\t\t\t\t\t\t\t\tconst result = results[j];\n\t\t\t\t\t\t\t\tbatchResults.push({\n\t\t\t\t\t\t\t\t\tfollower_count: result.follower_count ?? 0,\n\t\t\t\t\t\t\t\t\tsource: result.source ?? 'unknown',\n\t\t\t\t\t\t\t\t\tsuccess: result.success ?? false,\n\t\t\t\t\t\t\t\t\terror: result.error,\n\t\t\t\t\t\t\t\t\turl: result.url,\n\t\t\t\t\t\t\t\t\t_originalIndex: chunk[j].index,\n\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} catch (err) {\n\t\t\t\t\t\t\t// If entire batch fails, mark all URLs in chunk as failed\n\t\t\t\t\t\t\tfor (const item of chunk) {\n\t\t\t\t\t\t\t\tbatchResults.push({\n\t\t\t\t\t\t\t\t\tfollower_count: 0,\n\t\t\t\t\t\t\t\t\tsource: 'error',\n\t\t\t\t\t\t\t\t\tsuccess: false,\n\t\t\t\t\t\t\t\t\terror: `Batch request failed: ${(err as Error).message}`,\n\t\t\t\t\t\t\t\t\turl: item.url,\n\t\t\t\t\t\t\t\t\t_originalIndex: item.index,\n\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\t// Combine invalid and batch results, sort by original index to maintain order\n\t\t\t\t\tconst allResults = [...invalidResults, ...batchResults];\n\t\t\t\t\tallResults.sort((a, b) => (a._originalIndex as number) - (b._originalIndex as number));\n\n\t\t\t\t\t// Remove internal _originalIndex field and add to returnData\n\t\t\t\t\tfor (const result of allResults) {\n\t\t\t\t\t\tconst { _originalIndex: _, ...cleanResult } = result;\n\t\t\t\t\t\treturnData.push(cleanResult);\n\t\t\t\t\t}\n\n\t\t\t\t\t// Skip further iterations since we processed all items\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tthrow new NodeApiError(this.getNode(), {\n\t\t\t\t\tmessage: `Unsupported resource (${resource}) or operation (${operation})`,\n\t\t\t\t});\n\t\t\t} catch (error) {\n\t\t\t\tconst errorMessage = (error as any).message ?? (error as Error).message;\n\n\t\t\t\t// Check for authentication errors from the scraper service\n\t\t\t\tif ((error as any).statusCode === 401 || (error as any).statusCode === 403 || errorMessage.includes('401') || errorMessage.includes('403')) {\n\t\t\t\t\tthrow new NodeApiError(this.getNode(), {\n\t\t\t\t\t\tmessage: 'LinkedIn session expired. Please visit LinkedIn in a browser with the InNotes extension enabled to renew your session.',\n\t\t\t\t\t});\n\t\t\t\t}\n\n\t\t\t\tif (this.continueOnFail()) {\n\t\t\t\t\treturnData.push({\n\t\t\t\t\t\terror: errorMessage,\n\t\t\t\t\t\titemIndex,\n\t\t\t\t\t});\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t}\n\n\t\treturn [returnData.map((data) => ({ json: data }))];\n\t}\n}\n"]}
|
package/dist/package.json
CHANGED
|
@@ -18,6 +18,71 @@ describe('LinkedinScraper Node', () => {
|
|
|
18
18
|
expect((_a = node.description.credentials) === null || _a === void 0 ? void 0 : _a.map((cred) => cred.name)).toContain('inNotesApi');
|
|
19
19
|
});
|
|
20
20
|
});
|
|
21
|
+
// The InNotes credential used to carry an authMethod field, and this node
|
|
22
|
+
// refused to run unless it read back exactly 'token'. 3b8c1e46 deleted
|
|
23
|
+
// username/password auth and that field with it, but only from the
|
|
24
|
+
// credential — so the guard was left reading a property nothing writes and
|
|
25
|
+
// the n8n UI cannot set. Every credential without the stale leftover value
|
|
26
|
+
// failed with "requires Bearer token authentication", which asked people to
|
|
27
|
+
// pick an option that no longer exists on the screen.
|
|
28
|
+
//
|
|
29
|
+
// These tests pass a credential shaped exactly like the current credential
|
|
30
|
+
// type: no authMethod anywhere.
|
|
31
|
+
describe('Credentials', () => {
|
|
32
|
+
const credentialWithoutAuthMethod = {
|
|
33
|
+
baseUrl: 'https://innotes.me',
|
|
34
|
+
token: 'test-token-123',
|
|
35
|
+
callbackSecret: 'whatever',
|
|
36
|
+
allowedDomains: '*',
|
|
37
|
+
};
|
|
38
|
+
const makeContext = (credentials, request) => ({
|
|
39
|
+
getInputData: () => [{ json: {} }],
|
|
40
|
+
getCredentials: jest.fn().mockResolvedValue(credentials),
|
|
41
|
+
getNode: () => ({ name: 'LinkedIn Scraper' }),
|
|
42
|
+
getNodeParameter: (name) => {
|
|
43
|
+
if (name === 'resource')
|
|
44
|
+
return 'company';
|
|
45
|
+
if (name === 'operation')
|
|
46
|
+
return 'followers';
|
|
47
|
+
if (name === 'companyUrl')
|
|
48
|
+
return 'https://www.linkedin.com/company/acme';
|
|
49
|
+
return undefined;
|
|
50
|
+
},
|
|
51
|
+
continueOnFail: () => false,
|
|
52
|
+
helpers: { request },
|
|
53
|
+
});
|
|
54
|
+
it('authenticates with a credential that has no authMethod', async () => {
|
|
55
|
+
const request = jest.fn().mockResolvedValue({
|
|
56
|
+
results: [
|
|
57
|
+
{ follower_count: 42, source: 'linkedin', success: true, url: 'https://www.linkedin.com/company/acme' },
|
|
58
|
+
],
|
|
59
|
+
});
|
|
60
|
+
const node = new LinkedinScraper_node_1.LinkedinScraper();
|
|
61
|
+
await node.execute.call(makeContext(credentialWithoutAuthMethod, request));
|
|
62
|
+
expect(request).toHaveBeenCalledTimes(1);
|
|
63
|
+
expect(request.mock.calls[0][0].headers.Authorization).toBe('Bearer test-token-123');
|
|
64
|
+
});
|
|
65
|
+
it('does not ask the user to select a Bearer Token option that no longer exists', async () => {
|
|
66
|
+
const request = jest.fn().mockResolvedValue({ results: [] });
|
|
67
|
+
const node = new LinkedinScraper_node_1.LinkedinScraper();
|
|
68
|
+
const failure = await node.execute
|
|
69
|
+
.call(makeContext(credentialWithoutAuthMethod, request))
|
|
70
|
+
.then(() => '', (error) => error.message);
|
|
71
|
+
expect(failure).not.toMatch(/requires Bearer token authentication/);
|
|
72
|
+
});
|
|
73
|
+
it('still refuses a credential with no token at all', async () => {
|
|
74
|
+
const request = jest.fn();
|
|
75
|
+
const node = new LinkedinScraper_node_1.LinkedinScraper();
|
|
76
|
+
await expect(node.execute.call(makeContext({ baseUrl: 'https://innotes.me' }, request))).rejects.toThrow(/Bearer token is missing/);
|
|
77
|
+
expect(request).not.toHaveBeenCalled();
|
|
78
|
+
});
|
|
79
|
+
it('still refuses when the credential is missing entirely', async () => {
|
|
80
|
+
const request = jest.fn();
|
|
81
|
+
const node = new LinkedinScraper_node_1.LinkedinScraper();
|
|
82
|
+
await expect(node.execute.call(makeContext(null, request))).rejects.toThrow(/credentials are missing/);
|
|
83
|
+
expect(request).not.toHaveBeenCalled();
|
|
84
|
+
});
|
|
85
|
+
});
|
|
21
86
|
describe('Company Followers', () => {
|
|
22
87
|
it('should have company resource with followers operation', () => {
|
|
23
88
|
const node = new LinkedinScraper_node_1.LinkedinScraper();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../test/LinkedinScraper.node.test.ts"],"names":[],"mappings":"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","file":"LinkedinScraper.node.test.js","sourcesContent":["import { LinkedinScraper } from '../nodes/LinkedinScraper/LinkedinScraper.node';\nimport { INodePropertyOptions } from 'n8n-workflow';\n\ndescribe('LinkedinScraper Node', () => {\n\tdescribe('Node Properties', () => {\n\t\tit('should expose jobs, job, and company resources', () => {\n\t\t\tconst node = new LinkedinScraper();\n\t\t\tconst resources = node.description.properties\n\t\t\t\t.filter((property) => property.name === 'resource')\n\t\t\t\t.flatMap((property) => ('options' in property ? property.options : []))\n\t\t\t\t.filter((option): option is INodePropertyOptions => option !== undefined && 'value' in option)\n\t\t\t\t.map((option) => option.value);\n\n\t\t\texpect(resources).toEqual(expect.arrayContaining(['jobs', 'job', 'company']));\n\t\t});\n\n\t\tit('should require inNotesApi credentials', () => {\n\t\t\tconst node = new LinkedinScraper();\n\t\t\texpect(node.description.credentials?.map((cred) => cred.name)).toContain('inNotesApi');\n\t\t});\n\t});\n\n\tdescribe('Company Followers', () => {\n\t\tit('should have company resource with followers operation', () => {\n\t\t\tconst node = new LinkedinScraper();\n\t\t\tconst companyOps = node.description.properties\n\t\t\t\t.filter(\n\t\t\t\t\t(p) =>\n\t\t\t\t\t\tp.name === 'operation' && p.displayOptions?.show?.resource?.includes('company'),\n\t\t\t\t)\n\t\t\t\t.flatMap((p) => ('options' in p ? p.options : []))\n\t\t\t\t.filter((o): o is INodePropertyOptions => o !== undefined && 'value' in o)\n\t\t\t\t.map((o) => o.value);\n\n\t\t\texpect(companyOps).toContain('followers');\n\t\t});\n\n\t\tit('should require companyUrl parameter for followers operation', () => {\n\t\t\tconst node = new LinkedinScraper();\n\t\t\tconst companyUrlParam = node.description.properties.find((p) => p.name === 'companyUrl');\n\n\t\t\texpect(companyUrlParam).toBeDefined();\n\t\t\texpect(companyUrlParam?.required).toBe(true);\n\t\t});\n\n\t\tit('should have correct displayOptions for companyUrl', () => {\n\t\t\tconst node = new LinkedinScraper();\n\t\t\tconst companyUrlParam = node.description.properties.find((p) => p.name === 'companyUrl');\n\n\t\t\texpect(companyUrlParam?.displayOptions?.show?.resource).toContain('company');\n\t\t\texpect(companyUrlParam?.displayOptions?.show?.operation).toContain('followers');\n\t\t});\n\t});\n\n\tdescribe('Job Details Batch Operations', () => {\n\t\tit('should have job resource with details operation', () => {\n\t\t\tconst node = new LinkedinScraper();\n\t\t\tconst jobOps = node.description.properties\n\t\t\t\t.filter(\n\t\t\t\t\t(p) =>\n\t\t\t\t\t\tp.name === 'operation' && p.displayOptions?.show?.resource?.includes('job'),\n\t\t\t\t)\n\t\t\t\t.flatMap((p) => ('options' in p ? p.options : []))\n\t\t\t\t.filter((o): o is INodePropertyOptions => o !== undefined && 'value' in o)\n\t\t\t\t.map((o) => o.value);\n\n\t\t\texpect(jobOps).toContain('details');\n\t\t});\n\n\t\tit('should require jobUrl parameter for details operation', () => {\n\t\t\tconst node = new LinkedinScraper();\n\t\t\tconst jobUrlParam = node.description.properties.find((p) => p.name === 'jobUrl');\n\n\t\t\texpect(jobUrlParam).toBeDefined();\n\t\t\texpect(jobUrlParam?.required).toBe(true);\n\t\t});\n\n\t\tit('should have correct displayOptions for jobUrl', () => {\n\t\t\tconst node = new LinkedinScraper();\n\t\t\tconst jobUrlParam = node.description.properties.find((p) => p.name === 'jobUrl');\n\n\t\t\texpect(jobUrlParam?.displayOptions?.show?.resource).toContain('job');\n\t\t\texpect(jobUrlParam?.displayOptions?.show?.operation).toContain('details');\n\t\t});\n\t});\n\n\tdescribe('Batch Chunking Logic', () => {\n\t\tdescribe('Job Details Batch Chunking', () => {\n\t\t\tit('should chunk 30 job URLs into exactly 1 batch request', () => {\n\t\t\t\t// Verify CHUNK_SIZE constant is 30\n\t\t\t\tconst CHUNK_SIZE = 30;\n\t\t\t\tconst urlCount = 30;\n\t\t\t\tconst expectedBatches = Math.ceil(urlCount / CHUNK_SIZE);\n\t\t\t\texpect(expectedBatches).toBe(1);\n\t\t\t});\n\n\t\t\tit('should chunk 60 job URLs into exactly 2 batch requests', () => {\n\t\t\t\tconst CHUNK_SIZE = 30;\n\t\t\t\tconst urlCount = 60;\n\t\t\t\tconst expectedBatches = Math.ceil(urlCount / CHUNK_SIZE);\n\t\t\t\texpect(expectedBatches).toBe(2);\n\t\t\t});\n\n\t\t\tit('should chunk 31 job URLs into exactly 2 batch requests', () => {\n\t\t\t\tconst CHUNK_SIZE = 30;\n\t\t\t\tconst urlCount = 31;\n\t\t\t\tconst expectedBatches = Math.ceil(urlCount / CHUNK_SIZE);\n\t\t\t\texpect(expectedBatches).toBe(2);\n\t\t\t});\n\n\t\t\tit('should chunk 90 job URLs into exactly 3 batch requests', () => {\n\t\t\t\tconst CHUNK_SIZE = 30;\n\t\t\t\tconst urlCount = 90;\n\t\t\t\tconst expectedBatches = Math.ceil(urlCount / CHUNK_SIZE);\n\t\t\t\texpect(expectedBatches).toBe(3);\n\t\t\t});\n\t\t});\n\n\t\tdescribe('Company Followers Batch Chunking', () => {\n\t\t\tit('should chunk 30 company URLs into exactly 1 batch request', () => {\n\t\t\t\tconst CHUNK_SIZE = 30;\n\t\t\t\tconst urlCount = 30;\n\t\t\t\tconst expectedBatches = Math.ceil(urlCount / CHUNK_SIZE);\n\t\t\t\texpect(expectedBatches).toBe(1);\n\t\t\t});\n\n\t\t\tit('should chunk 60 company URLs into exactly 2 batch requests', () => {\n\t\t\t\tconst CHUNK_SIZE = 30;\n\t\t\t\tconst urlCount = 60;\n\t\t\t\tconst expectedBatches = Math.ceil(urlCount / CHUNK_SIZE);\n\t\t\t\texpect(expectedBatches).toBe(2);\n\t\t\t});\n\n\t\t\tit('should verify CHUNK_SIZE constant is 30 for company followers', () => {\n\t\t\t\t// This test documents the expected chunk size\n\t\t\t\tconst CHUNK_SIZE = 30;\n\t\t\t\texpect(CHUNK_SIZE).toBe(30);\n\t\t\t});\n\t\t});\n\t});\n\n\tdescribe('Batch Request Configuration', () => {\n\t\tdescribe('Job Details Batch Request', () => {\n\t\t\tit('should send max_concurrent = 15 in job details batch request', () => {\n\t\t\t\tconst max_concurrent = 15;\n\t\t\t\texpect(max_concurrent).toBe(15);\n\t\t\t});\n\n\t\t\tit('should send max_retries = 3 in job details batch request', () => {\n\t\t\t\tconst max_retries = 3;\n\t\t\t\texpect(max_retries).toBe(3);\n\t\t\t});\n\n\t\t\tit('should use 10 minute timeout for job details batch', () => {\n\t\t\t\tconst timeout = 10 * 60 * 1000;\n\t\t\t\texpect(timeout).toBe(600000);\n\t\t\t});\n\n\t\t\tit('should use POST method for job details batch endpoint', () => {\n\t\t\t\tconst method = 'POST';\n\t\t\t\texpect(method).toBe('POST');\n\t\t\t});\n\n\t\t\tit('should target /jobs/details/batch endpoint', () => {\n\t\t\t\tconst endpoint = '/jobs/details/batch';\n\t\t\t\texpect(endpoint).toContain('/jobs/details/batch');\n\t\t\t});\n\t\t});\n\n\t\tdescribe('Company Followers Batch Request', () => {\n\t\t\tit('should send max_concurrent = 15 in company followers batch request', () => {\n\t\t\t\tconst max_concurrent = 15;\n\t\t\t\texpect(max_concurrent).toBe(15);\n\t\t\t});\n\n\t\t\tit('should send max_retries = 3 in company followers batch request', () => {\n\t\t\t\tconst max_retries = 3;\n\t\t\t\texpect(max_retries).toBe(3);\n\t\t\t});\n\n\t\t\tit('should use 5 minute timeout for company followers batch', () => {\n\t\t\t\tconst timeout = 5 * 60 * 1000;\n\t\t\t\texpect(timeout).toBe(300000);\n\t\t\t});\n\n\t\t\tit('should use POST method for company followers batch endpoint', () => {\n\t\t\t\tconst method = 'POST';\n\t\t\t\texpect(method).toBe('POST');\n\t\t\t});\n\n\t\t\tit('should target /companies/followers/batch endpoint', () => {\n\t\t\t\tconst endpoint = '/companies/followers/batch';\n\t\t\t\texpect(endpoint).toContain('/companies/followers/batch');\n\t\t\t});\n\t\t});\n\t});\n\n\tdescribe('Error Resilience', () => {\n\t\tdescribe('Invalid URL Handling', () => {\n\t\t\tit('should produce error object for invalid job URL (not starting with http)', () => {\n\t\t\t\tconst invalidUrl = 'not-a-url';\n\t\t\t\tconst isValid = invalidUrl?.startsWith('http');\n\t\t\t\texpect(isValid).toBe(false);\n\n\t\t\t\t// Invalid URLs should produce error objects\n\t\t\t\tconst errorResult = {\n\t\t\t\t\tsuccess: false,\n\t\t\t\t\terror: `Invalid job URL: ${invalidUrl}`,\n\t\t\t\t\t_originalIndex: 0,\n\t\t\t\t};\n\t\t\t\texpect(errorResult.success).toBe(false);\n\t\t\t\texpect(errorResult.error).toContain('Invalid job URL');\n\t\t\t});\n\n\t\t\tit('should produce error object for empty job URL', () => {\n\t\t\t\tconst emptyUrl = '';\n\t\t\t\tconst isValid = emptyUrl?.startsWith('http');\n\t\t\t\texpect(isValid).toBe(false);\n\n\t\t\t\tconst errorResult = {\n\t\t\t\t\tsuccess: false,\n\t\t\t\t\terror: `Invalid job URL: ${emptyUrl || 'empty'}`,\n\t\t\t\t\t_originalIndex: 0,\n\t\t\t\t};\n\t\t\t\texpect(errorResult.success).toBe(false);\n\t\t\t\texpect(errorResult.error).toContain('Invalid job URL');\n\t\t\t});\n\n\t\t\tit('should produce error object for invalid company URL (not starting with http)', () => {\n\t\t\t\tconst invalidUrl = 'invalid-company-url';\n\t\t\t\tconst isValid = invalidUrl?.startsWith('http');\n\t\t\t\texpect(isValid).toBe(false);\n\n\t\t\t\tconst errorResult = {\n\t\t\t\t\tfollower_count: 0,\n\t\t\t\t\tsource: 'skipped',\n\t\t\t\t\tsuccess: false,\n\t\t\t\t\terror: `Invalid company URL: ${invalidUrl}`,\n\t\t\t\t\t_originalIndex: 0,\n\t\t\t\t};\n\t\t\t\texpect(errorResult.success).toBe(false);\n\t\t\t\texpect(errorResult.error).toContain('Invalid company URL');\n\t\t\t});\n\n\t\t\tit('should preserve original index for invalid URLs', () => {\n\t\t\t\tconst invalidUrl = 'not-a-url';\n\t\t\t\tconst originalIndex = 5;\n\n\t\t\t\tconst errorResult = {\n\t\t\t\t\tsuccess: false,\n\t\t\t\t\terror: `Invalid job URL: ${invalidUrl}`,\n\t\t\t\t\t_originalIndex: originalIndex,\n\t\t\t\t};\n\t\t\t\texpect(errorResult._originalIndex).toBe(5);\n\t\t\t});\n\t\t});\n\n\t\tdescribe('Batch Failure Handling', () => {\n\t\t\tit('should mark all URLs in chunk as failed when batch request fails', () => {\n\t\t\t\tconst chunkUrls = [\n\t\t\t\t\t'https://linkedin.com/jobs/view/1',\n\t\t\t\t\t'https://linkedin.com/jobs/view/2',\n\t\t\t\t\t'https://linkedin.com/jobs/view/3',\n\t\t\t\t];\n\t\t\t\tconst errorMessage = 'Network timeout';\n\n\t\t\t\t// When batch fails, all URLs in chunk get error objects\n\t\t\t\tconst failedResults = chunkUrls.map((url, idx) => ({\n\t\t\t\t\tsuccess: false,\n\t\t\t\t\terror: `Batch request failed: ${errorMessage}`,\n\t\t\t\t\turl,\n\t\t\t\t\t_originalIndex: idx,\n\t\t\t\t}));\n\n\t\t\t\texpect(failedResults).toHaveLength(3);\n\t\t\t\texpect(failedResults.every((r) => r.success === false)).toBe(true);\n\t\t\t\texpect(failedResults.every((r) => r.error.includes('Batch request failed'))).toBe(true);\n\t\t\t});\n\n\t\t\tit('should preserve URL in error result for batch failure', () => {\n\t\t\t\tconst url = 'https://linkedin.com/jobs/view/123';\n\t\t\t\tconst errorResult = {\n\t\t\t\t\tsuccess: false,\n\t\t\t\t\terror: 'Batch request failed: Connection timeout',\n\t\t\t\t\turl,\n\t\t\t\t\t_originalIndex: 0,\n\t\t\t\t};\n\n\t\t\t\texpect(errorResult.url).toBe(url);\n\t\t\t\texpect(errorResult.success).toBe(false);\n\t\t\t});\n\t\t});\n\n\t\tdescribe('Result Order Preservation', () => {\n\t\t\tit('should preserve original input order via _originalIndex for job details', () => {\n\t\t\t\tconst results = [\n\t\t\t\t\t{ success: true, _originalIndex: 2 },\n\t\t\t\t\t{ success: false, _originalIndex: 0 },\n\t\t\t\t\t{ success: true, _originalIndex: 1 },\n\t\t\t\t];\n\n\t\t\t\t// Sort by original index to restore order\n\t\t\t\tconst sorted = [...results].sort((a, b) => a._originalIndex - b._originalIndex);\n\n\t\t\t\texpect(sorted[0]._originalIndex).toBe(0);\n\t\t\t\texpect(sorted[1]._originalIndex).toBe(1);\n\t\t\t\texpect(sorted[2]._originalIndex).toBe(2);\n\t\t\t});\n\n\t\t\tit('should preserve original input order via _originalIndex for company followers', () => {\n\t\t\t\tconst results = [\n\t\t\t\t\t{ follower_count: 1000, _originalIndex: 2 },\n\t\t\t\t\t{ follower_count: 500, _originalIndex: 0 },\n\t\t\t\t\t{ follower_count: 2000, _originalIndex: 1 },\n\t\t\t\t];\n\n\t\t\t\tconst sorted = [...results].sort((a, b) => a._originalIndex - b._originalIndex);\n\n\t\t\t\texpect(sorted[0]._originalIndex).toBe(0);\n\t\t\t\texpect(sorted[1]._originalIndex).toBe(1);\n\t\t\t\texpect(sorted[2]._originalIndex).toBe(2);\n\t\t\t});\n\n\t\t\tit('should remove _originalIndex from final output', () => {\n\t\t\t\tconst result = {\n\t\t\t\t\tsuccess: true,\n\t\t\t\t\tjob_title: 'Engineer',\n\t\t\t\t\t_originalIndex: 0,\n\t\t\t\t};\n\n\t\t\t\t// Destructure to remove _originalIndex\n\t\t\t\tconst { _originalIndex: _, ...cleanResult } = result;\n\n\t\t\t\texpect(cleanResult).not.toHaveProperty('_originalIndex');\n\t\t\t\texpect(cleanResult).toHaveProperty('success');\n\t\t\t\texpect(cleanResult).toHaveProperty('job_title');\n\t\t\t});\n\t\t});\n\n\t\tdescribe('Mixed Valid and Invalid URLs', () => {\n\t\t\tit('should handle mix of valid and invalid job URLs', () => {\n\t\t\t\tconst items = [\n\t\t\t\t\t{ url: 'https://linkedin.com/jobs/view/1', valid: true },\n\t\t\t\t\t{ url: 'invalid-url', valid: false },\n\t\t\t\t\t{ url: 'https://linkedin.com/jobs/view/2', valid: true },\n\t\t\t\t\t{ url: '', valid: false },\n\t\t\t\t];\n\n\t\t\t\tconst validUrls = items.filter((item) => item.url?.startsWith('http'));\n\t\t\t\tconst invalidUrls = items.filter((item) => !item.url?.startsWith('http'));\n\n\t\t\t\texpect(validUrls).toHaveLength(2);\n\t\t\t\texpect(invalidUrls).toHaveLength(2);\n\t\t\t});\n\n\t\t\tit('should process valid URLs in batch while returning error objects for invalid ones', () => {\n\t\t\t\tconst validUrls = [\n\t\t\t\t\t{ url: 'https://linkedin.com/jobs/view/1', index: 0 },\n\t\t\t\t\t{ url: 'https://linkedin.com/jobs/view/2', index: 2 },\n\t\t\t\t];\n\t\t\t\tconst invalidResults = [\n\t\t\t\t\t{ success: false, error: 'Invalid URL', _originalIndex: 1 },\n\t\t\t\t\t{ success: false, error: 'Invalid URL', _originalIndex: 3 },\n\t\t\t\t];\n\n\t\t\t\t// Combine results\n\t\t\t\tconst allResults = [...invalidResults];\n\t\t\t\texpect(allResults).toHaveLength(2);\n\t\t\t\texpect(validUrls).toHaveLength(2);\n\t\t\t\texpect(allResults.every((r) => r.success === false)).toBe(true);\n\t\t\t});\n\t\t});\n\n\t\tdescribe('Auth Error Handling', () => {\n\t\t\tit('should re-throw 401 authentication errors', () => {\n\t\t\t\tconst statusCode: number = 401;\n\t\t\t\tconst shouldRethrow = statusCode === 401 || statusCode === 403;\n\t\t\t\texpect(shouldRethrow).toBe(true);\n\t\t\t});\n\n\t\t\tit('should re-throw 403 forbidden errors', () => {\n\t\t\t\tconst statusCode: number = 403;\n\t\t\t\tconst shouldRethrow = statusCode === 401 || statusCode === 403;\n\t\t\t\texpect(shouldRethrow).toBe(true);\n\t\t\t});\n\n\t\t\tit('should not re-throw other HTTP errors (e.g., 500)', () => {\n\t\t\t\tconst statusCode: number = 500;\n\t\t\t\tconst shouldRethrow = statusCode === 401 || statusCode === 403;\n\t\t\t\texpect(shouldRethrow).toBe(false);\n\t\t\t});\n\n\t\t\tit('should detect 401 in error message string', () => {\n\t\t\t\tconst errorMessage = 'HTTP 401: Unauthorized';\n\t\t\t\tconst is401 = errorMessage.includes('401');\n\t\t\t\texpect(is401).toBe(true);\n\t\t\t});\n\n\t\t\tit('should detect 403 in error message string', () => {\n\t\t\t\tconst errorMessage = 'HTTP 403: Forbidden';\n\t\t\t\tconst is403 = errorMessage.includes('403');\n\t\t\t\texpect(is403).toBe(true);\n\t\t\t});\n\t\t});\n\t});\n\n\tdescribe('Search Jobs Deduplication', () => {\n\t\tit('should remove duplicate jobs with the same link, keeping first occurrence', () => {\n\t\t\tconst jobs = [\n\t\t\t\t{ link: 'https://www.linkedin.com/jobs/view/111/', title: 'Engineer' },\n\t\t\t\t{ link: 'https://www.linkedin.com/jobs/view/222/', title: 'Designer' },\n\t\t\t\t{ link: 'https://www.linkedin.com/jobs/view/111/', title: 'Engineer (duplicate)' },\n\t\t\t\t{ link: 'https://www.linkedin.com/jobs/view/333/', title: 'Manager' },\n\t\t\t\t{ link: 'https://www.linkedin.com/jobs/view/222/', title: 'Designer (duplicate)' },\n\t\t\t];\n\n\t\t\tconst seenLinks = new Set<string>();\n\t\t\tconst uniqueJobs: Record<string, unknown>[] = [];\n\t\t\tfor (const job of jobs) {\n\t\t\t\tconst link = (job.link as string) || '';\n\t\t\t\tif (link && seenLinks.has(link)) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tif (link) {\n\t\t\t\t\tseenLinks.add(link);\n\t\t\t\t}\n\t\t\t\tuniqueJobs.push(job);\n\t\t\t}\n\n\t\t\texpect(uniqueJobs).toHaveLength(3);\n\t\t\texpect(uniqueJobs[0].title).toBe('Engineer');\n\t\t\texpect(uniqueJobs[1].title).toBe('Designer');\n\t\t\texpect(uniqueJobs[2].title).toBe('Manager');\n\t\t});\n\n\t\tit('should keep jobs without a link field', () => {\n\t\t\tconst jobs = [\n\t\t\t\t{ link: 'https://www.linkedin.com/jobs/view/111/', title: 'With Link' },\n\t\t\t\t{ title: 'No Link' },\n\t\t\t\t{ link: '', title: 'Empty Link' },\n\t\t\t];\n\n\t\t\tconst seenLinks = new Set<string>();\n\t\t\tconst uniqueJobs: Record<string, unknown>[] = [];\n\t\t\tfor (const job of jobs) {\n\t\t\t\tconst link = ((job as Record<string, unknown>).link as string) || '';\n\t\t\t\tif (link && seenLinks.has(link)) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tif (link) {\n\t\t\t\t\tseenLinks.add(link);\n\t\t\t\t}\n\t\t\t\tuniqueJobs.push(job);\n\t\t\t}\n\n\t\t\texpect(uniqueJobs).toHaveLength(3);\n\t\t});\n\t});\n\n\tdescribe('Batch Response Mapping', () => {\n\t\tdescribe('Job Details Result Mapping', () => {\n\t\t\tit('should map batch response results with all required fields', () => {\n\t\t\t\tconst batchResponse = {\n\t\t\t\t\tresults: [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\turl: 'https://linkedin.com/jobs/view/1',\n\t\t\t\t\t\t\tjob_title: 'Senior Engineer',\n\t\t\t\t\t\t\tcompany: 'Google',\n\t\t\t\t\t\t\tcompany_url: 'https://linkedin.com/company/google',\n\t\t\t\t\t\t\tpicture_url: 'https://example.com/pic.jpg',\n\t\t\t\t\t\t\tlocation: 'Mountain View, CA',\n\t\t\t\t\t\t\tjob_description: 'We are hiring...',\n\t\t\t\t\t\t\tsuccess: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t],\n\t\t\t\t};\n\n\t\t\t\tconst result = batchResponse.results[0];\n\t\t\t\texpect(result).toHaveProperty('url');\n\t\t\t\texpect(result).toHaveProperty('job_title');\n\t\t\t\texpect(result).toHaveProperty('company');\n\t\t\t\texpect(result).toHaveProperty('company_url');\n\t\t\t\texpect(result).toHaveProperty('picture_url');\n\t\t\t\texpect(result).toHaveProperty('location');\n\t\t\t\texpect(result).toHaveProperty('job_description');\n\t\t\t\texpect(result).toHaveProperty('success');\n\t\t\t});\n\n\t\t\tit('should preserve original index during result mapping', () => {\n\t\t\t\tconst chunk = [\n\t\t\t\t\t{ url: 'https://linkedin.com/jobs/view/1', index: 0 },\n\t\t\t\t\t{ url: 'https://linkedin.com/jobs/view/2', index: 1 },\n\t\t\t\t];\n\t\t\t\tconst batchResults = [\n\t\t\t\t\t{ url: 'https://linkedin.com/jobs/view/1', job_title: 'Job 1', success: true },\n\t\t\t\t\t{ url: 'https://linkedin.com/jobs/view/2', job_title: 'Job 2', success: true },\n\t\t\t\t];\n\n\t\t\t\t// Map results back with original indices\n\t\t\t\tconst mappedResults = batchResults.map((result, j) => ({\n\t\t\t\t\t...result,\n\t\t\t\t\t_originalIndex: chunk[j].index,\n\t\t\t\t}));\n\n\t\t\t\texpect(mappedResults[0]._originalIndex).toBe(0);\n\t\t\t\texpect(mappedResults[1]._originalIndex).toBe(1);\n\t\t\t});\n\t\t});\n\n\t\tdescribe('Company Followers Result Mapping', () => {\n\t\t\tit('should map batch response results with follower_count and source', () => {\n\t\t\t\tconst batchResponse = {\n\t\t\t\t\tresults: [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\turl: 'https://linkedin.com/company/google',\n\t\t\t\t\t\t\tfollower_count: 1000000,\n\t\t\t\t\t\t\tsource: 'linkedin',\n\t\t\t\t\t\t\tsuccess: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t],\n\t\t\t\t};\n\n\t\t\t\tconst result = batchResponse.results[0];\n\t\t\t\texpect(result).toHaveProperty('url');\n\t\t\t\texpect(result).toHaveProperty('follower_count');\n\t\t\t\texpect(result).toHaveProperty('source');\n\t\t\t\texpect(result).toHaveProperty('success');\n\t\t\t});\n\n\t\t\tit('should handle cached results with source: cache', () => {\n\t\t\t\tconst cachedResult = {\n\t\t\t\t\turl: 'https://linkedin.com/company/google',\n\t\t\t\t\tfollower_count: 1000000,\n\t\t\t\t\tsource: 'cache',\n\t\t\t\t\tsuccess: true,\n\t\t\t\t};\n\n\t\t\t\texpect(cachedResult.source).toBe('cache');\n\t\t\t\texpect(cachedResult.success).toBe(true);\n\t\t\t});\n\n\t\t\tit('should handle error results with source: error', () => {\n\t\t\t\tconst errorResult = {\n\t\t\t\t\turl: 'https://linkedin.com/company/invalid',\n\t\t\t\t\tfollower_count: 0,\n\t\t\t\t\tsource: 'error',\n\t\t\t\t\tsuccess: false,\n\t\t\t\t\terror: 'Company not found',\n\t\t\t\t};\n\n\t\t\t\texpect(errorResult.source).toBe('error');\n\t\t\t\texpect(errorResult.success).toBe(false);\n\t\t\t\texpect(errorResult.error).toBeDefined();\n\t\t\t});\n\t\t});\n\t});\n});\n"]}
|
|
1
|
+
{"version":3,"sources":["../test/LinkedinScraper.node.test.ts"],"names":[],"mappings":"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","file":"LinkedinScraper.node.test.js","sourcesContent":["import { LinkedinScraper } from '../nodes/LinkedinScraper/LinkedinScraper.node';\nimport { INodePropertyOptions } from 'n8n-workflow';\n\ndescribe('LinkedinScraper Node', () => {\n\tdescribe('Node Properties', () => {\n\t\tit('should expose jobs, job, and company resources', () => {\n\t\t\tconst node = new LinkedinScraper();\n\t\t\tconst resources = node.description.properties\n\t\t\t\t.filter((property) => property.name === 'resource')\n\t\t\t\t.flatMap((property) => ('options' in property ? property.options : []))\n\t\t\t\t.filter((option): option is INodePropertyOptions => option !== undefined && 'value' in option)\n\t\t\t\t.map((option) => option.value);\n\n\t\t\texpect(resources).toEqual(expect.arrayContaining(['jobs', 'job', 'company']));\n\t\t});\n\n\t\tit('should require inNotesApi credentials', () => {\n\t\t\tconst node = new LinkedinScraper();\n\t\t\texpect(node.description.credentials?.map((cred) => cred.name)).toContain('inNotesApi');\n\t\t});\n\t});\n\n\t// The InNotes credential used to carry an authMethod field, and this node\n\t// refused to run unless it read back exactly 'token'. 3b8c1e46 deleted\n\t// username/password auth and that field with it, but only from the\n\t// credential — so the guard was left reading a property nothing writes and\n\t// the n8n UI cannot set. Every credential without the stale leftover value\n\t// failed with \"requires Bearer token authentication\", which asked people to\n\t// pick an option that no longer exists on the screen.\n\t//\n\t// These tests pass a credential shaped exactly like the current credential\n\t// type: no authMethod anywhere.\n\tdescribe('Credentials', () => {\n\t\tconst credentialWithoutAuthMethod = {\n\t\t\tbaseUrl: 'https://innotes.me',\n\t\t\ttoken: 'test-token-123',\n\t\t\tcallbackSecret: 'whatever',\n\t\t\tallowedDomains: '*',\n\t\t};\n\n\t\tconst makeContext = (credentials: unknown, request: jest.Mock) => ({\n\t\t\tgetInputData: () => [{ json: {} }],\n\t\t\tgetCredentials: jest.fn().mockResolvedValue(credentials),\n\t\t\tgetNode: () => ({ name: 'LinkedIn Scraper' }),\n\t\t\tgetNodeParameter: (name: string) => {\n\t\t\t\tif (name === 'resource') return 'company';\n\t\t\t\tif (name === 'operation') return 'followers';\n\t\t\t\tif (name === 'companyUrl') return 'https://www.linkedin.com/company/acme';\n\t\t\t\treturn undefined;\n\t\t\t},\n\t\t\tcontinueOnFail: () => false,\n\t\t\thelpers: { request },\n\t\t});\n\n\t\tit('authenticates with a credential that has no authMethod', async () => {\n\t\t\tconst request = jest.fn().mockResolvedValue({\n\t\t\t\tresults: [\n\t\t\t\t\t{ follower_count: 42, source: 'linkedin', success: true, url: 'https://www.linkedin.com/company/acme' },\n\t\t\t\t],\n\t\t\t});\n\n\t\t\tconst node = new LinkedinScraper();\n\t\t\tawait node.execute.call(makeContext(credentialWithoutAuthMethod, request) as any);\n\n\t\t\texpect(request).toHaveBeenCalledTimes(1);\n\t\t\texpect(request.mock.calls[0][0].headers.Authorization).toBe('Bearer test-token-123');\n\t\t});\n\n\t\tit('does not ask the user to select a Bearer Token option that no longer exists', async () => {\n\t\t\tconst request = jest.fn().mockResolvedValue({ results: [] });\n\t\t\tconst node = new LinkedinScraper();\n\n\t\t\tconst failure = await node.execute\n\t\t\t\t.call(makeContext(credentialWithoutAuthMethod, request) as any)\n\t\t\t\t.then(\n\t\t\t\t\t() => '',\n\t\t\t\t\t(error: Error) => error.message,\n\t\t\t\t);\n\n\t\t\texpect(failure).not.toMatch(/requires Bearer token authentication/);\n\t\t});\n\n\t\tit('still refuses a credential with no token at all', async () => {\n\t\t\tconst request = jest.fn();\n\t\t\tconst node = new LinkedinScraper();\n\n\t\t\tawait expect(\n\t\t\t\tnode.execute.call(makeContext({ baseUrl: 'https://innotes.me' }, request) as any),\n\t\t\t).rejects.toThrow(/Bearer token is missing/);\n\t\t\texpect(request).not.toHaveBeenCalled();\n\t\t});\n\n\t\tit('still refuses when the credential is missing entirely', async () => {\n\t\t\tconst request = jest.fn();\n\t\t\tconst node = new LinkedinScraper();\n\n\t\t\tawait expect(\n\t\t\t\tnode.execute.call(makeContext(null, request) as any),\n\t\t\t).rejects.toThrow(/credentials are missing/);\n\t\t\texpect(request).not.toHaveBeenCalled();\n\t\t});\n\t});\n\n\tdescribe('Company Followers', () => {\n\t\tit('should have company resource with followers operation', () => {\n\t\t\tconst node = new LinkedinScraper();\n\t\t\tconst companyOps = node.description.properties\n\t\t\t\t.filter(\n\t\t\t\t\t(p) =>\n\t\t\t\t\t\tp.name === 'operation' && p.displayOptions?.show?.resource?.includes('company'),\n\t\t\t\t)\n\t\t\t\t.flatMap((p) => ('options' in p ? p.options : []))\n\t\t\t\t.filter((o): o is INodePropertyOptions => o !== undefined && 'value' in o)\n\t\t\t\t.map((o) => o.value);\n\n\t\t\texpect(companyOps).toContain('followers');\n\t\t});\n\n\t\tit('should require companyUrl parameter for followers operation', () => {\n\t\t\tconst node = new LinkedinScraper();\n\t\t\tconst companyUrlParam = node.description.properties.find((p) => p.name === 'companyUrl');\n\n\t\t\texpect(companyUrlParam).toBeDefined();\n\t\t\texpect(companyUrlParam?.required).toBe(true);\n\t\t});\n\n\t\tit('should have correct displayOptions for companyUrl', () => {\n\t\t\tconst node = new LinkedinScraper();\n\t\t\tconst companyUrlParam = node.description.properties.find((p) => p.name === 'companyUrl');\n\n\t\t\texpect(companyUrlParam?.displayOptions?.show?.resource).toContain('company');\n\t\t\texpect(companyUrlParam?.displayOptions?.show?.operation).toContain('followers');\n\t\t});\n\t});\n\n\tdescribe('Job Details Batch Operations', () => {\n\t\tit('should have job resource with details operation', () => {\n\t\t\tconst node = new LinkedinScraper();\n\t\t\tconst jobOps = node.description.properties\n\t\t\t\t.filter(\n\t\t\t\t\t(p) =>\n\t\t\t\t\t\tp.name === 'operation' && p.displayOptions?.show?.resource?.includes('job'),\n\t\t\t\t)\n\t\t\t\t.flatMap((p) => ('options' in p ? p.options : []))\n\t\t\t\t.filter((o): o is INodePropertyOptions => o !== undefined && 'value' in o)\n\t\t\t\t.map((o) => o.value);\n\n\t\t\texpect(jobOps).toContain('details');\n\t\t});\n\n\t\tit('should require jobUrl parameter for details operation', () => {\n\t\t\tconst node = new LinkedinScraper();\n\t\t\tconst jobUrlParam = node.description.properties.find((p) => p.name === 'jobUrl');\n\n\t\t\texpect(jobUrlParam).toBeDefined();\n\t\t\texpect(jobUrlParam?.required).toBe(true);\n\t\t});\n\n\t\tit('should have correct displayOptions for jobUrl', () => {\n\t\t\tconst node = new LinkedinScraper();\n\t\t\tconst jobUrlParam = node.description.properties.find((p) => p.name === 'jobUrl');\n\n\t\t\texpect(jobUrlParam?.displayOptions?.show?.resource).toContain('job');\n\t\t\texpect(jobUrlParam?.displayOptions?.show?.operation).toContain('details');\n\t\t});\n\t});\n\n\tdescribe('Batch Chunking Logic', () => {\n\t\tdescribe('Job Details Batch Chunking', () => {\n\t\t\tit('should chunk 30 job URLs into exactly 1 batch request', () => {\n\t\t\t\t// Verify CHUNK_SIZE constant is 30\n\t\t\t\tconst CHUNK_SIZE = 30;\n\t\t\t\tconst urlCount = 30;\n\t\t\t\tconst expectedBatches = Math.ceil(urlCount / CHUNK_SIZE);\n\t\t\t\texpect(expectedBatches).toBe(1);\n\t\t\t});\n\n\t\t\tit('should chunk 60 job URLs into exactly 2 batch requests', () => {\n\t\t\t\tconst CHUNK_SIZE = 30;\n\t\t\t\tconst urlCount = 60;\n\t\t\t\tconst expectedBatches = Math.ceil(urlCount / CHUNK_SIZE);\n\t\t\t\texpect(expectedBatches).toBe(2);\n\t\t\t});\n\n\t\t\tit('should chunk 31 job URLs into exactly 2 batch requests', () => {\n\t\t\t\tconst CHUNK_SIZE = 30;\n\t\t\t\tconst urlCount = 31;\n\t\t\t\tconst expectedBatches = Math.ceil(urlCount / CHUNK_SIZE);\n\t\t\t\texpect(expectedBatches).toBe(2);\n\t\t\t});\n\n\t\t\tit('should chunk 90 job URLs into exactly 3 batch requests', () => {\n\t\t\t\tconst CHUNK_SIZE = 30;\n\t\t\t\tconst urlCount = 90;\n\t\t\t\tconst expectedBatches = Math.ceil(urlCount / CHUNK_SIZE);\n\t\t\t\texpect(expectedBatches).toBe(3);\n\t\t\t});\n\t\t});\n\n\t\tdescribe('Company Followers Batch Chunking', () => {\n\t\t\tit('should chunk 30 company URLs into exactly 1 batch request', () => {\n\t\t\t\tconst CHUNK_SIZE = 30;\n\t\t\t\tconst urlCount = 30;\n\t\t\t\tconst expectedBatches = Math.ceil(urlCount / CHUNK_SIZE);\n\t\t\t\texpect(expectedBatches).toBe(1);\n\t\t\t});\n\n\t\t\tit('should chunk 60 company URLs into exactly 2 batch requests', () => {\n\t\t\t\tconst CHUNK_SIZE = 30;\n\t\t\t\tconst urlCount = 60;\n\t\t\t\tconst expectedBatches = Math.ceil(urlCount / CHUNK_SIZE);\n\t\t\t\texpect(expectedBatches).toBe(2);\n\t\t\t});\n\n\t\t\tit('should verify CHUNK_SIZE constant is 30 for company followers', () => {\n\t\t\t\t// This test documents the expected chunk size\n\t\t\t\tconst CHUNK_SIZE = 30;\n\t\t\t\texpect(CHUNK_SIZE).toBe(30);\n\t\t\t});\n\t\t});\n\t});\n\n\tdescribe('Batch Request Configuration', () => {\n\t\tdescribe('Job Details Batch Request', () => {\n\t\t\tit('should send max_concurrent = 15 in job details batch request', () => {\n\t\t\t\tconst max_concurrent = 15;\n\t\t\t\texpect(max_concurrent).toBe(15);\n\t\t\t});\n\n\t\t\tit('should send max_retries = 3 in job details batch request', () => {\n\t\t\t\tconst max_retries = 3;\n\t\t\t\texpect(max_retries).toBe(3);\n\t\t\t});\n\n\t\t\tit('should use 10 minute timeout for job details batch', () => {\n\t\t\t\tconst timeout = 10 * 60 * 1000;\n\t\t\t\texpect(timeout).toBe(600000);\n\t\t\t});\n\n\t\t\tit('should use POST method for job details batch endpoint', () => {\n\t\t\t\tconst method = 'POST';\n\t\t\t\texpect(method).toBe('POST');\n\t\t\t});\n\n\t\t\tit('should target /jobs/details/batch endpoint', () => {\n\t\t\t\tconst endpoint = '/jobs/details/batch';\n\t\t\t\texpect(endpoint).toContain('/jobs/details/batch');\n\t\t\t});\n\t\t});\n\n\t\tdescribe('Company Followers Batch Request', () => {\n\t\t\tit('should send max_concurrent = 15 in company followers batch request', () => {\n\t\t\t\tconst max_concurrent = 15;\n\t\t\t\texpect(max_concurrent).toBe(15);\n\t\t\t});\n\n\t\t\tit('should send max_retries = 3 in company followers batch request', () => {\n\t\t\t\tconst max_retries = 3;\n\t\t\t\texpect(max_retries).toBe(3);\n\t\t\t});\n\n\t\t\tit('should use 5 minute timeout for company followers batch', () => {\n\t\t\t\tconst timeout = 5 * 60 * 1000;\n\t\t\t\texpect(timeout).toBe(300000);\n\t\t\t});\n\n\t\t\tit('should use POST method for company followers batch endpoint', () => {\n\t\t\t\tconst method = 'POST';\n\t\t\t\texpect(method).toBe('POST');\n\t\t\t});\n\n\t\t\tit('should target /companies/followers/batch endpoint', () => {\n\t\t\t\tconst endpoint = '/companies/followers/batch';\n\t\t\t\texpect(endpoint).toContain('/companies/followers/batch');\n\t\t\t});\n\t\t});\n\t});\n\n\tdescribe('Error Resilience', () => {\n\t\tdescribe('Invalid URL Handling', () => {\n\t\t\tit('should produce error object for invalid job URL (not starting with http)', () => {\n\t\t\t\tconst invalidUrl = 'not-a-url';\n\t\t\t\tconst isValid = invalidUrl?.startsWith('http');\n\t\t\t\texpect(isValid).toBe(false);\n\n\t\t\t\t// Invalid URLs should produce error objects\n\t\t\t\tconst errorResult = {\n\t\t\t\t\tsuccess: false,\n\t\t\t\t\terror: `Invalid job URL: ${invalidUrl}`,\n\t\t\t\t\t_originalIndex: 0,\n\t\t\t\t};\n\t\t\t\texpect(errorResult.success).toBe(false);\n\t\t\t\texpect(errorResult.error).toContain('Invalid job URL');\n\t\t\t});\n\n\t\t\tit('should produce error object for empty job URL', () => {\n\t\t\t\tconst emptyUrl = '';\n\t\t\t\tconst isValid = emptyUrl?.startsWith('http');\n\t\t\t\texpect(isValid).toBe(false);\n\n\t\t\t\tconst errorResult = {\n\t\t\t\t\tsuccess: false,\n\t\t\t\t\terror: `Invalid job URL: ${emptyUrl || 'empty'}`,\n\t\t\t\t\t_originalIndex: 0,\n\t\t\t\t};\n\t\t\t\texpect(errorResult.success).toBe(false);\n\t\t\t\texpect(errorResult.error).toContain('Invalid job URL');\n\t\t\t});\n\n\t\t\tit('should produce error object for invalid company URL (not starting with http)', () => {\n\t\t\t\tconst invalidUrl = 'invalid-company-url';\n\t\t\t\tconst isValid = invalidUrl?.startsWith('http');\n\t\t\t\texpect(isValid).toBe(false);\n\n\t\t\t\tconst errorResult = {\n\t\t\t\t\tfollower_count: 0,\n\t\t\t\t\tsource: 'skipped',\n\t\t\t\t\tsuccess: false,\n\t\t\t\t\terror: `Invalid company URL: ${invalidUrl}`,\n\t\t\t\t\t_originalIndex: 0,\n\t\t\t\t};\n\t\t\t\texpect(errorResult.success).toBe(false);\n\t\t\t\texpect(errorResult.error).toContain('Invalid company URL');\n\t\t\t});\n\n\t\t\tit('should preserve original index for invalid URLs', () => {\n\t\t\t\tconst invalidUrl = 'not-a-url';\n\t\t\t\tconst originalIndex = 5;\n\n\t\t\t\tconst errorResult = {\n\t\t\t\t\tsuccess: false,\n\t\t\t\t\terror: `Invalid job URL: ${invalidUrl}`,\n\t\t\t\t\t_originalIndex: originalIndex,\n\t\t\t\t};\n\t\t\t\texpect(errorResult._originalIndex).toBe(5);\n\t\t\t});\n\t\t});\n\n\t\tdescribe('Batch Failure Handling', () => {\n\t\t\tit('should mark all URLs in chunk as failed when batch request fails', () => {\n\t\t\t\tconst chunkUrls = [\n\t\t\t\t\t'https://linkedin.com/jobs/view/1',\n\t\t\t\t\t'https://linkedin.com/jobs/view/2',\n\t\t\t\t\t'https://linkedin.com/jobs/view/3',\n\t\t\t\t];\n\t\t\t\tconst errorMessage = 'Network timeout';\n\n\t\t\t\t// When batch fails, all URLs in chunk get error objects\n\t\t\t\tconst failedResults = chunkUrls.map((url, idx) => ({\n\t\t\t\t\tsuccess: false,\n\t\t\t\t\terror: `Batch request failed: ${errorMessage}`,\n\t\t\t\t\turl,\n\t\t\t\t\t_originalIndex: idx,\n\t\t\t\t}));\n\n\t\t\t\texpect(failedResults).toHaveLength(3);\n\t\t\t\texpect(failedResults.every((r) => r.success === false)).toBe(true);\n\t\t\t\texpect(failedResults.every((r) => r.error.includes('Batch request failed'))).toBe(true);\n\t\t\t});\n\n\t\t\tit('should preserve URL in error result for batch failure', () => {\n\t\t\t\tconst url = 'https://linkedin.com/jobs/view/123';\n\t\t\t\tconst errorResult = {\n\t\t\t\t\tsuccess: false,\n\t\t\t\t\terror: 'Batch request failed: Connection timeout',\n\t\t\t\t\turl,\n\t\t\t\t\t_originalIndex: 0,\n\t\t\t\t};\n\n\t\t\t\texpect(errorResult.url).toBe(url);\n\t\t\t\texpect(errorResult.success).toBe(false);\n\t\t\t});\n\t\t});\n\n\t\tdescribe('Result Order Preservation', () => {\n\t\t\tit('should preserve original input order via _originalIndex for job details', () => {\n\t\t\t\tconst results = [\n\t\t\t\t\t{ success: true, _originalIndex: 2 },\n\t\t\t\t\t{ success: false, _originalIndex: 0 },\n\t\t\t\t\t{ success: true, _originalIndex: 1 },\n\t\t\t\t];\n\n\t\t\t\t// Sort by original index to restore order\n\t\t\t\tconst sorted = [...results].sort((a, b) => a._originalIndex - b._originalIndex);\n\n\t\t\t\texpect(sorted[0]._originalIndex).toBe(0);\n\t\t\t\texpect(sorted[1]._originalIndex).toBe(1);\n\t\t\t\texpect(sorted[2]._originalIndex).toBe(2);\n\t\t\t});\n\n\t\t\tit('should preserve original input order via _originalIndex for company followers', () => {\n\t\t\t\tconst results = [\n\t\t\t\t\t{ follower_count: 1000, _originalIndex: 2 },\n\t\t\t\t\t{ follower_count: 500, _originalIndex: 0 },\n\t\t\t\t\t{ follower_count: 2000, _originalIndex: 1 },\n\t\t\t\t];\n\n\t\t\t\tconst sorted = [...results].sort((a, b) => a._originalIndex - b._originalIndex);\n\n\t\t\t\texpect(sorted[0]._originalIndex).toBe(0);\n\t\t\t\texpect(sorted[1]._originalIndex).toBe(1);\n\t\t\t\texpect(sorted[2]._originalIndex).toBe(2);\n\t\t\t});\n\n\t\t\tit('should remove _originalIndex from final output', () => {\n\t\t\t\tconst result = {\n\t\t\t\t\tsuccess: true,\n\t\t\t\t\tjob_title: 'Engineer',\n\t\t\t\t\t_originalIndex: 0,\n\t\t\t\t};\n\n\t\t\t\t// Destructure to remove _originalIndex\n\t\t\t\tconst { _originalIndex: _, ...cleanResult } = result;\n\n\t\t\t\texpect(cleanResult).not.toHaveProperty('_originalIndex');\n\t\t\t\texpect(cleanResult).toHaveProperty('success');\n\t\t\t\texpect(cleanResult).toHaveProperty('job_title');\n\t\t\t});\n\t\t});\n\n\t\tdescribe('Mixed Valid and Invalid URLs', () => {\n\t\t\tit('should handle mix of valid and invalid job URLs', () => {\n\t\t\t\tconst items = [\n\t\t\t\t\t{ url: 'https://linkedin.com/jobs/view/1', valid: true },\n\t\t\t\t\t{ url: 'invalid-url', valid: false },\n\t\t\t\t\t{ url: 'https://linkedin.com/jobs/view/2', valid: true },\n\t\t\t\t\t{ url: '', valid: false },\n\t\t\t\t];\n\n\t\t\t\tconst validUrls = items.filter((item) => item.url?.startsWith('http'));\n\t\t\t\tconst invalidUrls = items.filter((item) => !item.url?.startsWith('http'));\n\n\t\t\t\texpect(validUrls).toHaveLength(2);\n\t\t\t\texpect(invalidUrls).toHaveLength(2);\n\t\t\t});\n\n\t\t\tit('should process valid URLs in batch while returning error objects for invalid ones', () => {\n\t\t\t\tconst validUrls = [\n\t\t\t\t\t{ url: 'https://linkedin.com/jobs/view/1', index: 0 },\n\t\t\t\t\t{ url: 'https://linkedin.com/jobs/view/2', index: 2 },\n\t\t\t\t];\n\t\t\t\tconst invalidResults = [\n\t\t\t\t\t{ success: false, error: 'Invalid URL', _originalIndex: 1 },\n\t\t\t\t\t{ success: false, error: 'Invalid URL', _originalIndex: 3 },\n\t\t\t\t];\n\n\t\t\t\t// Combine results\n\t\t\t\tconst allResults = [...invalidResults];\n\t\t\t\texpect(allResults).toHaveLength(2);\n\t\t\t\texpect(validUrls).toHaveLength(2);\n\t\t\t\texpect(allResults.every((r) => r.success === false)).toBe(true);\n\t\t\t});\n\t\t});\n\n\t\tdescribe('Auth Error Handling', () => {\n\t\t\tit('should re-throw 401 authentication errors', () => {\n\t\t\t\tconst statusCode: number = 401;\n\t\t\t\tconst shouldRethrow = statusCode === 401 || statusCode === 403;\n\t\t\t\texpect(shouldRethrow).toBe(true);\n\t\t\t});\n\n\t\t\tit('should re-throw 403 forbidden errors', () => {\n\t\t\t\tconst statusCode: number = 403;\n\t\t\t\tconst shouldRethrow = statusCode === 401 || statusCode === 403;\n\t\t\t\texpect(shouldRethrow).toBe(true);\n\t\t\t});\n\n\t\t\tit('should not re-throw other HTTP errors (e.g., 500)', () => {\n\t\t\t\tconst statusCode: number = 500;\n\t\t\t\tconst shouldRethrow = statusCode === 401 || statusCode === 403;\n\t\t\t\texpect(shouldRethrow).toBe(false);\n\t\t\t});\n\n\t\t\tit('should detect 401 in error message string', () => {\n\t\t\t\tconst errorMessage = 'HTTP 401: Unauthorized';\n\t\t\t\tconst is401 = errorMessage.includes('401');\n\t\t\t\texpect(is401).toBe(true);\n\t\t\t});\n\n\t\t\tit('should detect 403 in error message string', () => {\n\t\t\t\tconst errorMessage = 'HTTP 403: Forbidden';\n\t\t\t\tconst is403 = errorMessage.includes('403');\n\t\t\t\texpect(is403).toBe(true);\n\t\t\t});\n\t\t});\n\t});\n\n\tdescribe('Search Jobs Deduplication', () => {\n\t\tit('should remove duplicate jobs with the same link, keeping first occurrence', () => {\n\t\t\tconst jobs = [\n\t\t\t\t{ link: 'https://www.linkedin.com/jobs/view/111/', title: 'Engineer' },\n\t\t\t\t{ link: 'https://www.linkedin.com/jobs/view/222/', title: 'Designer' },\n\t\t\t\t{ link: 'https://www.linkedin.com/jobs/view/111/', title: 'Engineer (duplicate)' },\n\t\t\t\t{ link: 'https://www.linkedin.com/jobs/view/333/', title: 'Manager' },\n\t\t\t\t{ link: 'https://www.linkedin.com/jobs/view/222/', title: 'Designer (duplicate)' },\n\t\t\t];\n\n\t\t\tconst seenLinks = new Set<string>();\n\t\t\tconst uniqueJobs: Record<string, unknown>[] = [];\n\t\t\tfor (const job of jobs) {\n\t\t\t\tconst link = (job.link as string) || '';\n\t\t\t\tif (link && seenLinks.has(link)) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tif (link) {\n\t\t\t\t\tseenLinks.add(link);\n\t\t\t\t}\n\t\t\t\tuniqueJobs.push(job);\n\t\t\t}\n\n\t\t\texpect(uniqueJobs).toHaveLength(3);\n\t\t\texpect(uniqueJobs[0].title).toBe('Engineer');\n\t\t\texpect(uniqueJobs[1].title).toBe('Designer');\n\t\t\texpect(uniqueJobs[2].title).toBe('Manager');\n\t\t});\n\n\t\tit('should keep jobs without a link field', () => {\n\t\t\tconst jobs = [\n\t\t\t\t{ link: 'https://www.linkedin.com/jobs/view/111/', title: 'With Link' },\n\t\t\t\t{ title: 'No Link' },\n\t\t\t\t{ link: '', title: 'Empty Link' },\n\t\t\t];\n\n\t\t\tconst seenLinks = new Set<string>();\n\t\t\tconst uniqueJobs: Record<string, unknown>[] = [];\n\t\t\tfor (const job of jobs) {\n\t\t\t\tconst link = ((job as Record<string, unknown>).link as string) || '';\n\t\t\t\tif (link && seenLinks.has(link)) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tif (link) {\n\t\t\t\t\tseenLinks.add(link);\n\t\t\t\t}\n\t\t\t\tuniqueJobs.push(job);\n\t\t\t}\n\n\t\t\texpect(uniqueJobs).toHaveLength(3);\n\t\t});\n\t});\n\n\tdescribe('Batch Response Mapping', () => {\n\t\tdescribe('Job Details Result Mapping', () => {\n\t\t\tit('should map batch response results with all required fields', () => {\n\t\t\t\tconst batchResponse = {\n\t\t\t\t\tresults: [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\turl: 'https://linkedin.com/jobs/view/1',\n\t\t\t\t\t\t\tjob_title: 'Senior Engineer',\n\t\t\t\t\t\t\tcompany: 'Google',\n\t\t\t\t\t\t\tcompany_url: 'https://linkedin.com/company/google',\n\t\t\t\t\t\t\tpicture_url: 'https://example.com/pic.jpg',\n\t\t\t\t\t\t\tlocation: 'Mountain View, CA',\n\t\t\t\t\t\t\tjob_description: 'We are hiring...',\n\t\t\t\t\t\t\tsuccess: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t],\n\t\t\t\t};\n\n\t\t\t\tconst result = batchResponse.results[0];\n\t\t\t\texpect(result).toHaveProperty('url');\n\t\t\t\texpect(result).toHaveProperty('job_title');\n\t\t\t\texpect(result).toHaveProperty('company');\n\t\t\t\texpect(result).toHaveProperty('company_url');\n\t\t\t\texpect(result).toHaveProperty('picture_url');\n\t\t\t\texpect(result).toHaveProperty('location');\n\t\t\t\texpect(result).toHaveProperty('job_description');\n\t\t\t\texpect(result).toHaveProperty('success');\n\t\t\t});\n\n\t\t\tit('should preserve original index during result mapping', () => {\n\t\t\t\tconst chunk = [\n\t\t\t\t\t{ url: 'https://linkedin.com/jobs/view/1', index: 0 },\n\t\t\t\t\t{ url: 'https://linkedin.com/jobs/view/2', index: 1 },\n\t\t\t\t];\n\t\t\t\tconst batchResults = [\n\t\t\t\t\t{ url: 'https://linkedin.com/jobs/view/1', job_title: 'Job 1', success: true },\n\t\t\t\t\t{ url: 'https://linkedin.com/jobs/view/2', job_title: 'Job 2', success: true },\n\t\t\t\t];\n\n\t\t\t\t// Map results back with original indices\n\t\t\t\tconst mappedResults = batchResults.map((result, j) => ({\n\t\t\t\t\t...result,\n\t\t\t\t\t_originalIndex: chunk[j].index,\n\t\t\t\t}));\n\n\t\t\t\texpect(mappedResults[0]._originalIndex).toBe(0);\n\t\t\t\texpect(mappedResults[1]._originalIndex).toBe(1);\n\t\t\t});\n\t\t});\n\n\t\tdescribe('Company Followers Result Mapping', () => {\n\t\t\tit('should map batch response results with follower_count and source', () => {\n\t\t\t\tconst batchResponse = {\n\t\t\t\t\tresults: [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\turl: 'https://linkedin.com/company/google',\n\t\t\t\t\t\t\tfollower_count: 1000000,\n\t\t\t\t\t\t\tsource: 'linkedin',\n\t\t\t\t\t\t\tsuccess: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t],\n\t\t\t\t};\n\n\t\t\t\tconst result = batchResponse.results[0];\n\t\t\t\texpect(result).toHaveProperty('url');\n\t\t\t\texpect(result).toHaveProperty('follower_count');\n\t\t\t\texpect(result).toHaveProperty('source');\n\t\t\t\texpect(result).toHaveProperty('success');\n\t\t\t});\n\n\t\t\tit('should handle cached results with source: cache', () => {\n\t\t\t\tconst cachedResult = {\n\t\t\t\t\turl: 'https://linkedin.com/company/google',\n\t\t\t\t\tfollower_count: 1000000,\n\t\t\t\t\tsource: 'cache',\n\t\t\t\t\tsuccess: true,\n\t\t\t\t};\n\n\t\t\t\texpect(cachedResult.source).toBe('cache');\n\t\t\t\texpect(cachedResult.success).toBe(true);\n\t\t\t});\n\n\t\t\tit('should handle error results with source: error', () => {\n\t\t\t\tconst errorResult = {\n\t\t\t\t\turl: 'https://linkedin.com/company/invalid',\n\t\t\t\t\tfollower_count: 0,\n\t\t\t\t\tsource: 'error',\n\t\t\t\t\tsuccess: false,\n\t\t\t\t\terror: 'Company not found',\n\t\t\t\t};\n\n\t\t\t\texpect(errorResult.source).toBe('error');\n\t\t\t\texpect(errorResult.success).toBe(false);\n\t\t\t\texpect(errorResult.error).toBeDefined();\n\t\t\t});\n\t\t});\n\t});\n});\n"]}
|