blocket.js 1.3.0 → 1.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -10,8 +10,12 @@ import type { BlocketAd, BlocketQueryConfig } from '../types';
10
10
  export declare function find(query: BlocketQueryConfig, fetchOptions?: FetchOptions<'json', any>): Promise<BlocketAd[]>;
11
11
  /**
12
12
  * Get details of a specific ad by its ID.
13
+ *
14
+ * Note: The Blocket API no longer provides a public endpoint for single ad lookups.
15
+ * This method searches for the ad and returns it if found.
16
+ *
13
17
  * @param adId Advertisement ID.
14
18
  * @param fetchOptions Additional fetch options.
15
- * @returns {Promise<BlocketAd | null>} Blocket ad details or null if not found.
19
+ * @returns {Promise<BlocketAd | null>} Blocket ad or null if not found.
16
20
  */
17
21
  export declare function findById(adId: string, fetchOptions?: FetchOptions<'json', any>): Promise<BlocketAd | null>;
@@ -49,6 +49,7 @@ function remapQueryParams(params) {
49
49
  */
50
50
  function find(query, fetchOptions) {
51
51
  return __awaiter(this, void 0, void 0, function* () {
52
+ var _a;
52
53
  if (!query.query)
53
54
  throw new Error('Query string is required');
54
55
  const config = (0, config_1.getBaseConfig)();
@@ -56,21 +57,22 @@ function find(query, fetchOptions) {
56
57
  const params = remapQueryParams(queryConfig);
57
58
  const firstPageResponse = yield (0, request_1.apiRequest)(config.apiBaseUrl, Object.assign({ query: params }, fetchOptions));
58
59
  if (!firstPageResponse ||
59
- !firstPageResponse.data ||
60
- !Array.isArray(firstPageResponse.data)) {
61
- throw new Error(`Unexpected Blocket API response structure, expected array of ads, got: ${typeof (firstPageResponse === null || firstPageResponse === void 0 ? void 0 : firstPageResponse.data)}`);
60
+ !firstPageResponse.docs ||
61
+ !Array.isArray(firstPageResponse.docs)) {
62
+ throw new Error(`Unexpected Blocket API response structure, expected array of ads, got: ${typeof (firstPageResponse === null || firstPageResponse === void 0 ? void 0 : firstPageResponse.docs)}`);
62
63
  }
63
- if (firstPageResponse.total_page_count <= 1) {
64
- return firstPageResponse.data;
64
+ const paging = (_a = firstPageResponse.metadata) === null || _a === void 0 ? void 0 : _a.paging;
65
+ if (!paging || paging.last <= 1) {
66
+ return firstPageResponse.docs;
65
67
  }
66
- const allAds = [...firstPageResponse.data];
67
- const totalPages = firstPageResponse.total_page_count;
68
+ const allAds = [...firstPageResponse.docs];
69
+ const totalPages = paging.last;
68
70
  // Optimized pagination: Direct page parameter requests without delay
69
71
  for (let page = 2; page <= totalPages; page++) {
70
72
  const pageParams = Object.assign(Object.assign({}, params), { page });
71
73
  const response = yield (0, request_1.apiRequest)(config.apiBaseUrl, Object.assign({ query: pageParams }, fetchOptions));
72
- if (response && response.data && Array.isArray(response.data)) {
73
- allAds.push(...response.data);
74
+ if (response && response.docs && Array.isArray(response.docs)) {
75
+ allAds.push(...response.docs);
74
76
  }
75
77
  else {
76
78
  throw new Error(`Unexpected Blocket API response structure in paginated results, expected array of ads`);
@@ -81,19 +83,26 @@ function find(query, fetchOptions) {
81
83
  }
82
84
  /**
83
85
  * Get details of a specific ad by its ID.
86
+ *
87
+ * Note: The Blocket API no longer provides a public endpoint for single ad lookups.
88
+ * This method searches for the ad and returns it if found.
89
+ *
84
90
  * @param adId Advertisement ID.
85
91
  * @param fetchOptions Additional fetch options.
86
- * @returns {Promise<BlocketAd | null>} Blocket ad details or null if not found.
92
+ * @returns {Promise<BlocketAd | null>} Blocket ad or null if not found.
87
93
  */
88
94
  function findById(adId, fetchOptions) {
89
95
  return __awaiter(this, void 0, void 0, function* () {
90
96
  const config = (0, config_1.getBaseConfig)();
91
- const url = `${config.apiBaseUrl}/${adId}`;
92
- const ad = yield (0, request_1.apiRequest)(url, fetchOptions);
93
- if (!ad || !(ad === null || ad === void 0 ? void 0 : ad.data)) {
97
+ // Search with a generic query and filter by ID
98
+ // The API doesn't support direct ID lookup, so we use the ad ID as query
99
+ const response = yield (0, request_1.apiRequest)(config.apiBaseUrl, Object.assign({ query: { q: adId, lim: 100 } }, fetchOptions));
100
+ if (!response || !response.docs) {
94
101
  return null;
95
102
  }
96
- return ad.data;
103
+ // Find the exact ad by ID
104
+ const ad = response.docs.find((doc) => doc.id === adId || doc.ad_id === parseInt(adId, 10));
105
+ return ad || null;
97
106
  });
98
107
  }
99
108
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../lib/client/index.ts"],"names":[],"mappings":";;;;;;;;;;;AAuDA,oBA0DC;AAQD,4BAcC;AAvID,uCAAuC;AACvC,sCAA6D;AAW7D;;;;GAIG;AACH,SAAS,gBAAgB,CACvB,MAA0B;IAE1B,MAAM,OAAO,GAGT;QACF,KAAK,EAAE,GAAG;QACV,KAAK,EAAE,KAAK;QACZ,IAAI,EAAE,MAAM;QACZ,WAAW,EAAE,IAAI;QACjB,MAAM,EAAE,QAAQ;QAChB,WAAW,EAAE,IAAI;QACjB,OAAO,EAAE,SAAS;QAClB,IAAI,EAAE,MAAM;KACb,CAAC;IAEF,MAAM,QAAQ,GAAsC,EAAE,CAAC;IAEvD,KAAK,MAAM,GAAG,IAAI,MAAM,EAAE,CAAC;QACzB,IAAI,OAAO,CAAC,GAA+B,CAAC,EAAE,CAAC;YAC7C,MAAM,MAAM,GAAG,OAAO,CAAC,GAA+B,CAAC,CAAC;YACxD,MAAM,CAAC,MAAM,CAAC,QAAQ,EAAE;gBACtB,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC,GAA+B,CAAC;aAClD,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IAED,OAAO,QAAoC,CAAC;AAC9C,CAAC;AAED;;;;;;GAMG;AACH,SAAsB,IAAI,CACxB,KAAyB,EACzB,YAAwC;;QAExC,IAAI,CAAC,KAAK,CAAC,KAAK;YAAE,MAAM,IAAI,KAAK,CAAC,0BAA0B,CAAC,CAAC;QAE9D,MAAM,MAAM,GAAG,IAAA,sBAAa,GAAE,CAAC;QAC/B,MAAM,WAAW,GAAG,IAAA,0BAAiB,EAAC,KAAK,CAAC,CAAC;QAE7C,MAAM,MAAM,GAAG,gBAAgB,CAAC,WAAW,CAAC,CAAC;QAE7C,MAAM,iBAAiB,GAAG,MAAM,IAAA,oBAAU,EACxC,MAAM,CAAC,UAAU,kBAEf,KAAK,EAAE,MAAM,IACV,YAAY,EAElB,CAAC;QAEF,IACE,CAAC,iBAAiB;YAClB,CAAC,iBAAiB,CAAC,IAAI;YACvB,CAAC,KAAK,CAAC,OAAO,CAAC,iBAAiB,CAAC,IAAI,CAAC,EACtC,CAAC;YACD,MAAM,IAAI,KAAK,CACb,0EAA0E,OAAO,CAAA,iBAAiB,aAAjB,iBAAiB,uBAAjB,iBAAiB,CAAE,IAAI,CAAA,EAAE,CAC3G,CAAC;QACJ,CAAC;QAED,IAAI,iBAAiB,CAAC,gBAAgB,IAAI,CAAC,EAAE,CAAC;YAC5C,OAAO,iBAAiB,CAAC,IAAI,CAAC;QAChC,CAAC;QAED,MAAM,MAAM,GAAG,CAAC,GAAG,iBAAiB,CAAC,IAAI,CAAC,CAAC;QAC3C,MAAM,UAAU,GAAG,iBAAiB,CAAC,gBAAgB,CAAC;QAEtD,qEAAqE;QACrE,KAAK,IAAI,IAAI,GAAG,CAAC,EAAE,IAAI,IAAI,UAAU,EAAE,IAAI,EAAE,EAAE,CAAC;YAC9C,MAAM,UAAU,mCACX,MAAM,KACT,IAAI,GACL,CAAC;YAEF,MAAM,QAAQ,GAAG,MAAM,IAAA,oBAAU,EAAqB,MAAM,CAAC,UAAU,kBACrE,KAAK,EAAE,UAAU,IACd,YAAY,EACf,CAAC;YAEH,IAAI,QAAQ,IAAI,QAAQ,CAAC,IAAI,IAAI,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;gBAC9D,MAAM,CAAC,IAAI,CAAC,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC;YAChC,CAAC;iBAAM,CAAC;gBACN,MAAM,IAAI,KAAK,CACb,uFAAuF,CACxF,CAAC;YACJ,CAAC;QACH,CAAC;QAED,OAAO,MAAM,CAAC;IAChB,CAAC;CAAA;AAED;;;;;GAKG;AACH,SAAsB,QAAQ,CAC5B,IAAY,EACZ,YAAwC;;QAExC,MAAM,MAAM,GAAG,IAAA,sBAAa,GAAE,CAAC;QAC/B,MAAM,GAAG,GAAG,GAAG,MAAM,CAAC,UAAU,IAAI,IAAI,EAAE,CAAC;QAE3C,MAAM,EAAE,GAAG,MAAM,IAAA,oBAAU,EAAoB,GAAG,EAAE,YAAY,CAAC,CAAC;QAElE,IAAI,CAAC,EAAE,IAAI,CAAC,CAAA,EAAE,aAAF,EAAE,uBAAF,EAAE,CAAE,IAAI,CAAA,EAAE,CAAC;YACrB,OAAO,IAAI,CAAC;QACd,CAAC;QAED,OAAO,EAAE,CAAC,IAAI,CAAC;IACjB,CAAC;CAAA"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../lib/client/index.ts"],"names":[],"mappings":"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"}
@@ -1,9 +1,8 @@
1
1
  import { type FetchOptions } from 'ofetch';
2
2
  /**
3
- * Make an API request with automatic token handling and retry on 401 errors.
3
+ * Make an API request with User-Agent authentication.
4
4
  * @param url URL to fetch.
5
5
  * @param options Fetch options.
6
- * @param retryCount Current retry count.
7
6
  * @returns Parsed response of type T.
8
7
  */
9
- export declare function apiRequest<T>(url: string, options?: FetchOptions<'json', any>, retryCount?: number): Promise<T>;
8
+ export declare function apiRequest<T>(url: string, options?: FetchOptions<'json', any>): Promise<T>;
@@ -11,35 +11,22 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
11
11
  Object.defineProperty(exports, "__esModule", { value: true });
12
12
  exports.apiRequest = apiRequest;
13
13
  const ofetch_1 = require("ofetch");
14
- const token_1 = require("./token");
15
14
  const config_1 = require("../config");
16
15
  /**
17
- * Make an API request with automatic token handling and retry on 401 errors.
16
+ * Make an API request with User-Agent authentication.
18
17
  * @param url URL to fetch.
19
18
  * @param options Fetch options.
20
- * @param retryCount Current retry count.
21
19
  * @returns Parsed response of type T.
22
20
  */
23
21
  function apiRequest(url_1) {
24
- return __awaiter(this, arguments, void 0, function* (url, options = {}, retryCount = 0) {
25
- var _a;
26
- const config = (0, config_1.getBaseConfig)();
27
- const token = yield (0, token_1.fetchToken)();
22
+ return __awaiter(this, arguments, void 0, function* (url, options = {}) {
28
23
  try {
29
- const response = yield (0, ofetch_1.ofetch)(url, Object.assign(Object.assign({}, options), { headers: Object.assign(Object.assign({ 'Accept': 'application/json', 'Accept-Language': 'sv-SE,sv;q=0.9,en;q=0.8', 'Accept-Encoding': 'gzip, deflate, br', 'Connection': 'keep-alive', 'Referer': 'https://www.blocket.se/' }, options.headers), { Authorization: `Bearer ${token}` }) }));
30
- return response;
24
+ return yield (0, ofetch_1.ofetch)(url, Object.assign(Object.assign({}, options), { headers: Object.assign({ 'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64; rv:128.0) Gecko/20100101 Firefox/128.0' }, options.headers) }));
31
25
  }
32
26
  catch (error) {
33
- // Enhanced error handling for HTTP status codes
34
27
  if ((error === null || error === void 0 ? void 0 : error.status) >= 400) {
35
28
  (0, config_1.logger)('error', `HTTP ${error.status}: ${error.statusText || 'Request failed'}`);
36
29
  }
37
- if (((error === null || error === void 0 ? void 0 : error.status) === 401 || ((_a = error === null || error === void 0 ? void 0 : error.data) === null || _a === void 0 ? void 0 : _a.status_code) === 401) && retryCount < config.retryAttempts) {
38
- (0, config_1.logger)('info', `Token expired (${error.status}). Retrying request (${retryCount + 1}/${config.retryAttempts}).`);
39
- const newToken = yield (0, token_1.fetchToken)(true);
40
- (0, token_1.setCachedToken)(newToken);
41
- return apiRequest(url, options, retryCount + 1);
42
- }
43
30
  throw error;
44
31
  }
45
32
  });
@@ -1 +1 @@
1
- {"version":3,"file":"request.js","sourceRoot":"","sources":["../../lib/client/request.ts"],"names":[],"mappings":";;;;;;;;;;;AAYA,gCA0CC;AAtDD,mCAAmD;AAEnD,mCAAqD;AACrD,sCAAkD;AAElD;;;;;;GAMG;AACH,SAAsB,UAAU;yDAC9B,GAAW,EACX,UAAqC,EAAE,EACvC,aAAqB,CAAC;;QAEtB,MAAM,MAAM,GAAG,IAAA,sBAAa,GAAE,CAAC;QAC/B,MAAM,KAAK,GAAG,MAAM,IAAA,kBAAU,GAAE,CAAC;QAEjC,IAAI,CAAC;YACH,MAAM,QAAQ,GAAG,MAAM,IAAA,eAAM,EAAI,GAAG,kCAC/B,OAAO,KACV,OAAO,gCACL,QAAQ,EAAE,kBAAkB,EAC5B,iBAAiB,EAAE,yBAAyB,EAC5C,iBAAiB,EAAE,mBAAmB,EACtC,YAAY,EAAE,YAAY,EAC1B,SAAS,EAAE,yBAAyB,IACjC,OAAO,CAAC,OAAO,KAClB,aAAa,EAAE,UAAU,KAAK,EAAE,OAElC,CAAC;YAEH,OAAO,QAAQ,CAAC;QAClB,CAAC;QAAC,OAAO,KAAU,EAAE,CAAC;YACpB,gDAAgD;YAChD,IAAI,CAAA,KAAK,aAAL,KAAK,uBAAL,KAAK,CAAE,MAAM,KAAI,GAAG,EAAE,CAAC;gBACzB,IAAA,eAAM,EAAC,OAAO,EAAE,QAAQ,KAAK,CAAC,MAAM,KAAK,KAAK,CAAC,UAAU,IAAI,gBAAgB,EAAE,CAAC,CAAC;YACnF,CAAC;YAED,IAAI,CAAC,CAAA,KAAK,aAAL,KAAK,uBAAL,KAAK,CAAE,MAAM,MAAK,GAAG,IAAI,CAAA,MAAA,KAAK,aAAL,KAAK,uBAAL,KAAK,CAAE,IAAI,0CAAE,WAAW,MAAK,GAAG,CAAC,IAAI,UAAU,GAAG,MAAM,CAAC,aAAa,EAAE,CAAC;gBACrG,IAAA,eAAM,EACJ,MAAM,EACN,kBAAkB,KAAK,CAAC,MAAM,wBAAwB,UAAU,GAAG,CAAC,IAClE,MAAM,CAAC,aACT,IAAI,CACL,CAAC;gBACF,MAAM,QAAQ,GAAG,MAAM,IAAA,kBAAU,EAAC,IAAI,CAAC,CAAC;gBACxC,IAAA,sBAAc,EAAC,QAAQ,CAAC,CAAC;gBACzB,OAAO,UAAU,CAAI,GAAG,EAAE,OAAO,EAAE,UAAU,GAAG,CAAC,CAAC,CAAC;YACrD,CAAC;YACD,MAAM,KAAK,CAAC;QACd,CAAC;IACH,CAAC;CAAA"}
1
+ {"version":3,"file":"request.js","sourceRoot":"","sources":["../../lib/client/request.ts"],"names":[],"mappings":";;;;;;;;;;;AAUA,gCAsBC;AAhCD,mCAAmD;AAEnD,sCAAmC;AAEnC;;;;;GAKG;AACH,SAAsB,UAAU;yDAC9B,GAAW,EACX,UAAqC,EAAE;QAEvC,IAAI,CAAC;YACH,OAAO,MAAM,IAAA,eAAM,EAAI,GAAG,kCACrB,OAAO,KACV,OAAO,kBACL,YAAY,EACV,wEAAwE,IACvE,OAAO,CAAC,OAAO,KAEpB,CAAC;QACL,CAAC;QAAC,OAAO,KAAU,EAAE,CAAC;YACpB,IAAI,CAAA,KAAK,aAAL,KAAK,uBAAL,KAAK,CAAE,MAAM,KAAI,GAAG,EAAE,CAAC;gBACzB,IAAA,eAAM,EACJ,OAAO,EACP,QAAQ,KAAK,CAAC,MAAM,KAAK,KAAK,CAAC,UAAU,IAAI,gBAAgB,EAAE,CAChE,CAAC;YACJ,CAAC;YACD,MAAM,KAAK,CAAC;QACd,CAAC;IACH,CAAC;CAAA"}
@@ -5,10 +5,8 @@ exports.createQueryConfig = exports.defaultQueryConfig = exports.logger = export
5
5
  * Default global configuration.
6
6
  */
7
7
  exports.defaultConfig = {
8
- apiBaseUrl: 'https://api.blocket.se/search_bff/v2/content',
9
- tokenEndpoint: 'https://www.blocket.se/api/adout-api-route/refresh-token-and-validate-session',
8
+ apiBaseUrl: 'https://www.blocket.se/recommerce/forsale/search/api/search/SEARCH_ID_BAP_COMMON',
10
9
  logLevel: 'error',
11
- retryAttempts: 3,
12
10
  };
13
11
  let currentConfig = Object.assign({}, exports.defaultConfig);
14
12
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../lib/config/index.ts"],"names":[],"mappings":";;;AAEA;;GAEG;AACU,QAAA,aAAa,GAAkB;IAC1C,UAAU,EAAE,8CAA8C;IAC1D,aAAa,EACX,+EAA+E;IACjF,QAAQ,EAAE,OAAO;IACjB,aAAa,EAAE,CAAC;CACjB,CAAC;AAEF,IAAI,aAAa,qBAAuB,qBAAa,CAAE,CAAC;AAExD;;;GAGG;AACI,MAAM,SAAS,GAAG,CAAC,MAA8B,EAAQ,EAAE;IAChE,aAAa,mCAAQ,aAAa,GAAK,MAAM,CAAE,CAAC;AAClD,CAAC,CAAC;AAFW,QAAA,SAAS,aAEpB;AAEF;;;GAGG;AACI,MAAM,aAAa,GAAG,GAAkB,EAAE,CAAC,aAAa,CAAC;AAAnD,QAAA,aAAa,iBAAsC;AAEhE;;;;GAIG;AACI,MAAM,MAAM,GAAG,CACpB,KAAiC,EACjC,OAAe,EACT,EAAE;IACR,MAAM,MAAM,GAAG,EAAE,IAAI,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC;IACxD,IAAI,MAAM,CAAC,IAAA,qBAAa,GAAE,CAAC,QAAQ,CAAC,IAAI,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC;QACtD,OAAO,CAAC,KAAK,KAAK,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC;IACxD,CAAC;AACH,CAAC,CAAC;AARW,QAAA,MAAM,UAQjB;AAEF;;GAEG;AACU,QAAA,kBAAkB,GAAsC;IACnE,WAAW,EAAE,GAAG;IAChB,MAAM,EAAE,QAAQ;CACjB,CAAC;AAEF;;;;GAIG;AACI,MAAM,iBAAiB,GAAG,CAC/B,WAC4C,EACxB,EAAE;IACtB,uCAAY,0BAAkB,GAAK,WAAW,EAAG;AACnD,CAAC,CAAC;AALW,QAAA,iBAAiB,qBAK5B"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../lib/config/index.ts"],"names":[],"mappings":";;;AAEA;;GAEG;AACU,QAAA,aAAa,GAAkB;IAC1C,UAAU,EACR,kFAAkF;IACpF,QAAQ,EAAE,OAAO;CAClB,CAAC;AAEF,IAAI,aAAa,qBAAuB,qBAAa,CAAE,CAAC;AAExD;;;GAGG;AACI,MAAM,SAAS,GAAG,CAAC,MAA8B,EAAQ,EAAE;IAChE,aAAa,mCAAQ,aAAa,GAAK,MAAM,CAAE,CAAC;AAClD,CAAC,CAAC;AAFW,QAAA,SAAS,aAEpB;AAEF;;;GAGG;AACI,MAAM,aAAa,GAAG,GAAkB,EAAE,CAAC,aAAa,CAAC;AAAnD,QAAA,aAAa,iBAAsC;AAEhE;;;;GAIG;AACI,MAAM,MAAM,GAAG,CACpB,KAAiC,EACjC,OAAe,EACT,EAAE;IACR,MAAM,MAAM,GAAG,EAAE,IAAI,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC;IACxD,IAAI,MAAM,CAAC,IAAA,qBAAa,GAAE,CAAC,QAAQ,CAAC,IAAI,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC;QACtD,OAAO,CAAC,KAAK,KAAK,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC;IACxD,CAAC;AACH,CAAC,CAAC;AARW,QAAA,MAAM,UAQjB;AAEF;;GAEG;AACU,QAAA,kBAAkB,GAAsC;IACnE,WAAW,EAAE,GAAG;IAChB,MAAM,EAAE,QAAQ;CACjB,CAAC;AAEF;;;;GAIG;AACI,MAAM,iBAAiB,GAAG,CAC/B,WAC4C,EACxB,EAAE;IACtB,uCAAY,0BAAkB,GAAK,WAAW,EAAG;AACnD,CAAC,CAAC;AALW,QAAA,iBAAiB,qBAK5B"}
@@ -4,25 +4,15 @@
4
4
  export interface BlocketConfig {
5
5
  /**
6
6
  * Base URL for the Blocket API.
7
- * @default 'https://api.blocket.se/search_bff/v2/content'
7
+ * @default 'https://www.blocket.se/recommerce/forsale/search/api/search/SEARCH_ID_BAP_COMMON'
8
8
  */
9
9
  apiBaseUrl: string;
10
- /**
11
- * Endpoint URL to fetch the token.
12
- * @default 'https://www.blocket.se/api/adout-api-route/refresh-token-and-validate-session'
13
- */
14
- tokenEndpoint: string;
15
10
  /**
16
11
  * Log level for debugging.
17
12
  * Options: 'none', 'error', 'info', 'debug'
18
13
  * @default 'error'
19
14
  */
20
15
  logLevel: 'none' | 'error' | 'info' | 'debug';
21
- /**
22
- * Maximum number of retry attempts on 401 error.
23
- * @default 3
24
- */
25
- retryAttempts: number;
26
16
  }
27
17
  /**
28
18
  * Blocket Query Configuration interface.
@@ -1,95 +1,72 @@
1
1
  export * from './config';
2
2
  /**
3
- * Access token.
3
+ * Blocket API response containing an array of ads with metadata.
4
4
  */
5
- export type BlocketAccessToken = {
6
- user: null;
7
- isLoggedIn: false;
8
- bearerToken: string;
9
- };
10
- /**
11
- * Blocket API response containing a single ad.
12
- */
13
- export interface BlocketAdResponse {
14
- data: BlocketAd;
5
+ export interface BlocketApiResponse {
6
+ docs: BlocketAd[];
7
+ filters: unknown[];
8
+ metadata: BlocketMetadata;
15
9
  }
16
10
  /**
17
- * Blocket API response containing an array of ads with additional metadata.
11
+ * Blocket API metadata containing pagination and search info.
18
12
  */
19
- export interface BlocketApiResponse {
20
- data: BlocketAd[];
21
- gallery: unknown[];
22
- inventory: Record<string, unknown>;
23
- next_scroll_block: number;
24
- next_scroll_id: string;
25
- non_shipping_count: number;
26
- query_signature: string;
27
- saveable: boolean;
28
- selected_values: string;
29
- share_url: string;
13
+ export interface BlocketMetadata {
14
+ params: Record<string, string[]>;
15
+ search_key: string;
16
+ selected_filters: unknown[];
17
+ num_results: number;
18
+ result_size: {
19
+ match_count: number;
20
+ group_count: number;
21
+ };
22
+ paging: {
23
+ param: string;
24
+ current: number;
25
+ last: number;
26
+ };
30
27
  title: string;
31
- total_count: number;
32
- total_page_count: number;
28
+ is_savable_search: boolean;
29
+ is_end_of_paging: boolean;
30
+ timestamp: number;
33
31
  }
34
32
  /**
35
33
  * Blocket advertisement object.
36
34
  */
37
35
  export interface BlocketAd {
38
- ad_id: string;
39
- ad_status: 'active' | 'inactive' | string;
40
- advertiser: {
41
- account_id?: string;
42
- contact_methods: {
43
- phone: boolean;
44
- sms: boolean;
45
- };
46
- name: string;
47
- public_profile?: Record<string, any>;
48
- store_name?: string;
49
- type: 'private' | 'business' | 'store';
50
- };
51
- body: string;
52
- category: Array<{
53
- id: string;
54
- name: string;
55
- }>;
56
- co2_text?: string;
57
- images: Array<{
58
- height: number;
59
- type: string;
36
+ type: string;
37
+ id: string;
38
+ ad_id: number;
39
+ main_search_key: string;
40
+ heading: string;
41
+ location: string;
42
+ image: {
60
43
  url: string;
44
+ path: string;
45
+ height: number;
61
46
  width: number;
62
- }>;
63
- infopage?: {
64
- text: string;
65
- url: string;
47
+ aspect_ratio: number;
48
+ } | null;
49
+ image_urls: string[];
50
+ flags: string[];
51
+ timestamp: number;
52
+ coordinates?: {
53
+ lat: number;
54
+ lon: number;
55
+ accuracy: number;
66
56
  };
67
- list_id: string;
68
- list_time: string;
69
- location: Array<{
57
+ ad_type: number;
58
+ labels: Array<{
70
59
  id: string;
71
- name: string;
72
- parent_id?: string;
60
+ text: string;
61
+ type: 'PRIMARY' | 'SECONDARY' | string;
73
62
  }>;
74
- map_url: string;
75
- parameter_groups?: Record<string, any>[];
76
- parameters_raw?: {
77
- is_shipping_buy_now_enabled?: Record<string, any>;
78
- shipping_enabled?: Record<string, any>;
79
- };
80
- partner_info?: any;
63
+ canonical_url: string;
64
+ extras: unknown[];
81
65
  price: {
82
- suffix: string;
83
- value: number;
66
+ amount: number;
67
+ currency_code: string;
68
+ price_unit: string;
84
69
  };
85
- price_badge?: {
86
- icon: Record<string, any>;
87
- id: string;
88
- label: string;
89
- };
90
- share_url: string;
91
- state_id: string;
92
- subject: string;
93
- type: string;
94
- zipcode: string;
70
+ distance: number;
71
+ trade_type: string;
95
72
  }
@@ -5,7 +5,6 @@ import type { FetchOptions } from 'ofetch';
5
5
  import type {
6
6
  BlocketQueryParamsNative,
7
7
  BlocketAd,
8
- BlocketAdResponse,
9
8
  BlocketQueryConfig,
10
9
  BlocketApiResponse,
11
10
  } from '../types';
@@ -74,20 +73,21 @@ export async function find(
74
73
 
75
74
  if (
76
75
  !firstPageResponse ||
77
- !firstPageResponse.data ||
78
- !Array.isArray(firstPageResponse.data)
76
+ !firstPageResponse.docs ||
77
+ !Array.isArray(firstPageResponse.docs)
79
78
  ) {
80
79
  throw new Error(
81
- `Unexpected Blocket API response structure, expected array of ads, got: ${typeof firstPageResponse?.data}`
80
+ `Unexpected Blocket API response structure, expected array of ads, got: ${typeof firstPageResponse?.docs}`
82
81
  );
83
82
  }
84
83
 
85
- if (firstPageResponse.total_page_count <= 1) {
86
- return firstPageResponse.data;
84
+ const paging = firstPageResponse.metadata?.paging;
85
+ if (!paging || paging.last <= 1) {
86
+ return firstPageResponse.docs;
87
87
  }
88
88
 
89
- const allAds = [...firstPageResponse.data];
90
- const totalPages = firstPageResponse.total_page_count;
89
+ const allAds = [...firstPageResponse.docs];
90
+ const totalPages = paging.last;
91
91
 
92
92
  // Optimized pagination: Direct page parameter requests without delay
93
93
  for (let page = 2; page <= totalPages; page++) {
@@ -101,8 +101,8 @@ export async function find(
101
101
  ...fetchOptions,
102
102
  });
103
103
 
104
- if (response && response.data && Array.isArray(response.data)) {
105
- allAds.push(...response.data);
104
+ if (response && response.docs && Array.isArray(response.docs)) {
105
+ allAds.push(...response.docs);
106
106
  } else {
107
107
  throw new Error(
108
108
  `Unexpected Blocket API response structure in paginated results, expected array of ads`
@@ -115,22 +115,35 @@ export async function find(
115
115
 
116
116
  /**
117
117
  * Get details of a specific ad by its ID.
118
+ *
119
+ * Note: The Blocket API no longer provides a public endpoint for single ad lookups.
120
+ * This method searches for the ad and returns it if found.
121
+ *
118
122
  * @param adId Advertisement ID.
119
123
  * @param fetchOptions Additional fetch options.
120
- * @returns {Promise<BlocketAd | null>} Blocket ad details or null if not found.
124
+ * @returns {Promise<BlocketAd | null>} Blocket ad or null if not found.
121
125
  */
122
126
  export async function findById(
123
127
  adId: string,
124
128
  fetchOptions?: FetchOptions<'json', any>
125
129
  ): Promise<BlocketAd | null> {
126
130
  const config = getBaseConfig();
127
- const url = `${config.apiBaseUrl}/${adId}`;
128
131
 
129
- const ad = await apiRequest<BlocketAdResponse>(url, fetchOptions);
132
+ // Search with a generic query and filter by ID
133
+ // The API doesn't support direct ID lookup, so we use the ad ID as query
134
+ const response = await apiRequest<BlocketApiResponse>(config.apiBaseUrl, {
135
+ query: { q: adId, lim: 100 },
136
+ ...fetchOptions,
137
+ });
130
138
 
131
- if (!ad || !ad?.data) {
139
+ if (!response || !response.docs) {
132
140
  return null;
133
141
  }
134
142
 
135
- return ad.data;
143
+ // Find the exact ad by ID
144
+ const ad = response.docs.find(
145
+ (doc) => doc.id === adId || doc.ad_id === parseInt(adId, 10)
146
+ );
147
+
148
+ return ad || null;
136
149
  }
@@ -1,54 +1,32 @@
1
1
  import { ofetch, type FetchOptions } from 'ofetch';
2
2
 
3
- import { fetchToken, setCachedToken } from './token';
4
- import { getBaseConfig, logger } from '../config';
3
+ import { logger } from '../config';
5
4
 
6
5
  /**
7
- * Make an API request with automatic token handling and retry on 401 errors.
6
+ * Make an API request with User-Agent authentication.
8
7
  * @param url URL to fetch.
9
8
  * @param options Fetch options.
10
- * @param retryCount Current retry count.
11
9
  * @returns Parsed response of type T.
12
10
  */
13
11
  export async function apiRequest<T>(
14
12
  url: string,
15
- options: FetchOptions<'json', any> = {},
16
- retryCount: number = 0
13
+ options: FetchOptions<'json', any> = {}
17
14
  ): Promise<T> {
18
- const config = getBaseConfig();
19
- const token = await fetchToken();
20
-
21
15
  try {
22
- const response = await ofetch<T>(url, {
16
+ return await ofetch<T>(url, {
23
17
  ...options,
24
18
  headers: {
25
- 'Accept': 'application/json',
26
- 'Accept-Language': 'sv-SE,sv;q=0.9,en;q=0.8',
27
- 'Accept-Encoding': 'gzip, deflate, br',
28
- 'Connection': 'keep-alive',
29
- 'Referer': 'https://www.blocket.se/',
19
+ 'User-Agent':
20
+ 'Mozilla/5.0 (X11; Linux x86_64; rv:128.0) Gecko/20100101 Firefox/128.0',
30
21
  ...options.headers,
31
- Authorization: `Bearer ${token}`,
32
22
  },
33
23
  });
34
-
35
- return response;
36
24
  } catch (error: any) {
37
- // Enhanced error handling for HTTP status codes
38
25
  if (error?.status >= 400) {
39
- logger('error', `HTTP ${error.status}: ${error.statusText || 'Request failed'}`);
40
- }
41
-
42
- if ((error?.status === 401 || error?.data?.status_code === 401) && retryCount < config.retryAttempts) {
43
26
  logger(
44
- 'info',
45
- `Token expired (${error.status}). Retrying request (${retryCount + 1}/${
46
- config.retryAttempts
47
- }).`
27
+ 'error',
28
+ `HTTP ${error.status}: ${error.statusText || 'Request failed'}`
48
29
  );
49
- const newToken = await fetchToken(true);
50
- setCachedToken(newToken);
51
- return apiRequest<T>(url, options, retryCount + 1);
52
30
  }
53
31
  throw error;
54
32
  }
@@ -4,11 +4,9 @@ import { BlocketQueryConfig, BlocketConfig } from '../types';
4
4
  * Default global configuration.
5
5
  */
6
6
  export const defaultConfig: BlocketConfig = {
7
- apiBaseUrl: 'https://api.blocket.se/search_bff/v2/content',
8
- tokenEndpoint:
9
- 'https://www.blocket.se/api/adout-api-route/refresh-token-and-validate-session',
7
+ apiBaseUrl:
8
+ 'https://www.blocket.se/recommerce/forsale/search/api/search/SEARCH_ID_BAP_COMMON',
10
9
  logLevel: 'error',
11
- retryAttempts: 3,
12
10
  };
13
11
 
14
12
  let currentConfig: BlocketConfig = { ...defaultConfig };
@@ -4,25 +4,15 @@
4
4
  export interface BlocketConfig {
5
5
  /**
6
6
  * Base URL for the Blocket API.
7
- * @default 'https://api.blocket.se/search_bff/v2/content'
7
+ * @default 'https://www.blocket.se/recommerce/forsale/search/api/search/SEARCH_ID_BAP_COMMON'
8
8
  */
9
9
  apiBaseUrl: string;
10
- /**
11
- * Endpoint URL to fetch the token.
12
- * @default 'https://www.blocket.se/api/adout-api-route/refresh-token-and-validate-session'
13
- */
14
- tokenEndpoint: string;
15
10
  /**
16
11
  * Log level for debugging.
17
12
  * Options: 'none', 'error', 'info', 'debug'
18
13
  * @default 'error'
19
14
  */
20
15
  logLevel: 'none' | 'error' | 'info' | 'debug';
21
- /**
22
- * Maximum number of retry attempts on 401 error.
23
- * @default 3
24
- */
25
- retryAttempts: number;
26
16
  }
27
17
 
28
18
  /**
@@ -1,99 +1,76 @@
1
1
  export * from './config';
2
2
 
3
3
  /**
4
- * Access token.
4
+ * Blocket API response containing an array of ads with metadata.
5
5
  */
6
- export type BlocketAccessToken = {
7
- user: null;
8
- isLoggedIn: false;
9
- bearerToken: string;
10
- };
11
-
12
- /**
13
- * Blocket API response containing a single ad.
14
- */
15
- export interface BlocketAdResponse {
16
- data: BlocketAd;
6
+ export interface BlocketApiResponse {
7
+ docs: BlocketAd[];
8
+ filters: unknown[];
9
+ metadata: BlocketMetadata;
17
10
  }
18
11
 
19
12
  /**
20
- * Blocket API response containing an array of ads with additional metadata.
13
+ * Blocket API metadata containing pagination and search info.
21
14
  */
22
- export interface BlocketApiResponse {
23
- data: BlocketAd[];
24
- gallery: unknown[];
25
- inventory: Record<string, unknown>;
26
- next_scroll_block: number;
27
- next_scroll_id: string;
28
- non_shipping_count: number;
29
- query_signature: string;
30
- saveable: boolean;
31
- selected_values: string;
32
- share_url: string;
15
+ export interface BlocketMetadata {
16
+ params: Record<string, string[]>;
17
+ search_key: string;
18
+ selected_filters: unknown[];
19
+ num_results: number;
20
+ result_size: {
21
+ match_count: number;
22
+ group_count: number;
23
+ };
24
+ paging: {
25
+ param: string;
26
+ current: number;
27
+ last: number;
28
+ };
33
29
  title: string;
34
- total_count: number;
35
- total_page_count: number;
30
+ is_savable_search: boolean;
31
+ is_end_of_paging: boolean;
32
+ timestamp: number;
36
33
  }
37
34
 
38
35
  /**
39
36
  * Blocket advertisement object.
40
37
  */
41
38
  export interface BlocketAd {
42
- ad_id: string;
43
- ad_status: 'active' | 'inactive' | string;
44
- advertiser: {
45
- account_id?: string;
46
- contact_methods: {
47
- phone: boolean;
48
- sms: boolean;
49
- };
50
- name: string;
51
- public_profile?: Record<string, any>;
52
- store_name?: string; // For business listings
53
- type: 'private' | 'business' | 'store';
54
- };
55
- body: string;
56
- category: Array<{
57
- id: string;
58
- name: string;
59
- }>;
60
- co2_text?: string;
61
- images: Array<{
62
- height: number;
63
- type: string;
39
+ type: string;
40
+ id: string;
41
+ ad_id: number;
42
+ main_search_key: string;
43
+ heading: string;
44
+ location: string;
45
+ image: {
64
46
  url: string;
47
+ path: string;
48
+ height: number;
65
49
  width: number;
66
- }>;
67
- infopage?: {
68
- text: string;
69
- url: string;
70
- }; // External links for businesses
71
- list_id: string;
72
- list_time: string; // ISO date string
73
- location: Array<{
50
+ aspect_ratio: number;
51
+ } | null;
52
+ image_urls: string[];
53
+ flags: string[];
54
+ timestamp: number;
55
+ coordinates?: {
56
+ lat: number;
57
+ lon: number;
58
+ accuracy: number;
59
+ };
60
+ ad_type: number;
61
+ labels: Array<{
74
62
  id: string;
75
- name: string;
76
- parent_id?: string;
63
+ text: string;
64
+ type: 'PRIMARY' | 'SECONDARY' | string;
77
65
  }>;
78
- map_url: string;
79
- parameter_groups?: Record<string, any>[];
80
- parameters_raw?: {
81
- is_shipping_buy_now_enabled?: Record<string, any>;
82
- shipping_enabled?: Record<string, any>;
83
- };
84
- partner_info?: any;
66
+ canonical_url: string;
67
+ extras: unknown[];
85
68
  price: {
86
- suffix: string;
87
- value: number;
88
- };
89
- price_badge?: {
90
- icon: Record<string, any>;
91
- id: string;
92
- label: string;
69
+ amount: number;
70
+ currency_code: string;
71
+ price_unit: string;
93
72
  };
94
- share_url: string;
95
- state_id: string;
96
- subject: string;
97
- type: string;
98
- zipcode: string;
73
+ distance: number;
74
+ trade_type: string;
99
75
  }
76
+
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "blocket.js",
3
- "version": "1.3.0",
3
+ "version": "1.4.0",
4
4
  "description": "A user-friendly js wrapper for blocket.se",
5
5
  "keywords": [
6
6
  "blocket",
@@ -1,16 +0,0 @@
1
- /**
2
- * Get the cached token.
3
- * @returns Cached bearer token if available.
4
- */
5
- export declare const getCachedToken: () => string | null;
6
- /**
7
- * Set the cached token.
8
- * @param token Bearer token.
9
- */
10
- export declare const setCachedToken: (token: string) => void;
11
- /**
12
- * Fetch a new token from Blocket API.
13
- * @param forceRefresh If true, ignores cached token and fetches a new one.
14
- * @returns The bearer token.
15
- */
16
- export declare const fetchToken: (forceRefresh?: boolean) => Promise<string>;
@@ -1,56 +0,0 @@
1
- "use strict";
2
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
- return new (P || (P = Promise))(function (resolve, reject) {
5
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
- step((generator = generator.apply(thisArg, _arguments || [])).next());
9
- });
10
- };
11
- Object.defineProperty(exports, "__esModule", { value: true });
12
- exports.fetchToken = exports.setCachedToken = exports.getCachedToken = void 0;
13
- const ofetch_1 = require("ofetch");
14
- const config_1 = require("../config");
15
- let cachedToken = null;
16
- /**
17
- * Get the cached token.
18
- * @returns Cached bearer token if available.
19
- */
20
- const getCachedToken = () => cachedToken;
21
- exports.getCachedToken = getCachedToken;
22
- /**
23
- * Set the cached token.
24
- * @param token Bearer token.
25
- */
26
- const setCachedToken = (token) => {
27
- cachedToken = token;
28
- };
29
- exports.setCachedToken = setCachedToken;
30
- /**
31
- * Fetch a new token from Blocket API.
32
- * @param forceRefresh If true, ignores cached token and fetches a new one.
33
- * @returns The bearer token.
34
- */
35
- const fetchToken = (...args_1) => __awaiter(void 0, [...args_1], void 0, function* (forceRefresh = false) {
36
- if (!forceRefresh && cachedToken)
37
- return cachedToken;
38
- (0, config_1.logger)('debug', 'Fetching new Blocket API token.');
39
- const config = (0, config_1.getBaseConfig)();
40
- const tokenData = yield (0, ofetch_1.ofetch)(config.tokenEndpoint, {
41
- headers: {
42
- 'Accept': 'application/json',
43
- 'Accept-Language': 'sv-SE,sv;q=0.9,en;q=0.8',
44
- 'Accept-Encoding': 'gzip, deflate, br',
45
- 'Connection': 'keep-alive',
46
- 'Referer': 'https://www.blocket.se/',
47
- },
48
- });
49
- if (!tokenData || !tokenData.bearerToken) {
50
- throw new Error('Failed to retrieve Blocket API token.');
51
- }
52
- cachedToken = tokenData.bearerToken;
53
- return cachedToken;
54
- });
55
- exports.fetchToken = fetchToken;
56
- //# sourceMappingURL=token.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"token.js","sourceRoot":"","sources":["../../lib/client/token.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,mCAAgC;AAEhC,sCAAkD;AAIlD,IAAI,WAAW,GAAkB,IAAI,CAAC;AAEtC;;;GAGG;AACI,MAAM,cAAc,GAAG,GAAkB,EAAE,CAAC,WAAW,CAAC;AAAlD,QAAA,cAAc,kBAAoC;AAE/D;;;GAGG;AACI,MAAM,cAAc,GAAG,CAAC,KAAa,EAAQ,EAAE;IACpD,WAAW,GAAG,KAAK,CAAC;AACtB,CAAC,CAAC;AAFW,QAAA,cAAc,kBAEzB;AAEF;;;;GAIG;AACI,MAAM,UAAU,GAAG,YAEP,EAAE,mDADnB,eAAwB,KAAK;IAE7B,IAAI,CAAC,YAAY,IAAI,WAAW;QAAE,OAAO,WAAW,CAAC;IAErD,IAAA,eAAM,EAAC,OAAO,EAAE,iCAAiC,CAAC,CAAC;IAEnD,MAAM,MAAM,GAAG,IAAA,sBAAa,GAAE,CAAC;IAE/B,MAAM,SAAS,GAAG,MAAM,IAAA,eAAM,EAAqB,MAAM,CAAC,aAAa,EAAE;QACvE,OAAO,EAAE;YACP,QAAQ,EAAE,kBAAkB;YAC5B,iBAAiB,EAAE,yBAAyB;YAC5C,iBAAiB,EAAE,mBAAmB;YACtC,YAAY,EAAE,YAAY;YAC1B,SAAS,EAAE,yBAAyB;SACrC;KACF,CAAC,CAAC;IAEH,IAAI,CAAC,SAAS,IAAI,CAAC,SAAS,CAAC,WAAW,EAAE,CAAC;QACzC,MAAM,IAAI,KAAK,CAAC,uCAAuC,CAAC,CAAC;IAC3D,CAAC;IAED,WAAW,GAAG,SAAS,CAAC,WAAW,CAAC;IACpC,OAAO,WAAW,CAAC;AACrB,CAAC,CAAA,CAAC;AAzBW,QAAA,UAAU,cAyBrB"}
@@ -1,53 +0,0 @@
1
- import { ofetch } from 'ofetch';
2
-
3
- import { getBaseConfig, logger } from '../config';
4
-
5
- import type { BlocketAccessToken } from '../types';
6
-
7
- let cachedToken: string | null = null;
8
-
9
- /**
10
- * Get the cached token.
11
- * @returns Cached bearer token if available.
12
- */
13
- export const getCachedToken = (): string | null => cachedToken;
14
-
15
- /**
16
- * Set the cached token.
17
- * @param token Bearer token.
18
- */
19
- export const setCachedToken = (token: string): void => {
20
- cachedToken = token;
21
- };
22
-
23
- /**
24
- * Fetch a new token from Blocket API.
25
- * @param forceRefresh If true, ignores cached token and fetches a new one.
26
- * @returns The bearer token.
27
- */
28
- export const fetchToken = async (
29
- forceRefresh: boolean = false
30
- ): Promise<string> => {
31
- if (!forceRefresh && cachedToken) return cachedToken;
32
-
33
- logger('debug', 'Fetching new Blocket API token.');
34
-
35
- const config = getBaseConfig();
36
-
37
- const tokenData = await ofetch<BlocketAccessToken>(config.tokenEndpoint, {
38
- headers: {
39
- 'Accept': 'application/json',
40
- 'Accept-Language': 'sv-SE,sv;q=0.9,en;q=0.8',
41
- 'Accept-Encoding': 'gzip, deflate, br',
42
- 'Connection': 'keep-alive',
43
- 'Referer': 'https://www.blocket.se/',
44
- },
45
- });
46
-
47
- if (!tokenData || !tokenData.bearerToken) {
48
- throw new Error('Failed to retrieve Blocket API token.');
49
- }
50
-
51
- cachedToken = tokenData.bearerToken;
52
- return cachedToken;
53
- };