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.
- package/dist/client/index.d.ts +5 -1
- package/dist/client/index.js +23 -14
- package/dist/client/index.js.map +1 -1
- package/dist/client/request.d.ts +2 -3
- package/dist/client/request.js +3 -16
- package/dist/client/request.js.map +1 -1
- package/dist/config/index.js +1 -3
- package/dist/config/index.js.map +1 -1
- package/dist/types/config.d.ts +1 -11
- package/dist/types/index.d.ts +52 -75
- package/lib/client/index.ts +28 -15
- package/lib/client/request.ts +8 -30
- package/lib/config/index.ts +2 -4
- package/lib/types/config.ts +1 -11
- package/lib/types/index.ts +54 -77
- package/package.json +1 -1
- package/dist/client/token.d.ts +0 -16
- package/dist/client/token.js +0 -56
- package/dist/client/token.js.map +0 -1
- package/lib/client/token.ts +0 -53
package/dist/client/index.d.ts
CHANGED
|
@@ -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
|
|
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>;
|
package/dist/client/index.js
CHANGED
|
@@ -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.
|
|
60
|
-
!Array.isArray(firstPageResponse.
|
|
61
|
-
throw new Error(`Unexpected Blocket API response structure, expected array of ads, got: ${typeof (firstPageResponse === null || firstPageResponse === void 0 ? void 0 : firstPageResponse.
|
|
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
|
-
|
|
64
|
-
|
|
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.
|
|
67
|
-
const totalPages =
|
|
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.
|
|
73
|
-
allAds.push(...response.
|
|
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
|
|
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
|
-
|
|
92
|
-
|
|
93
|
-
|
|
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
|
-
|
|
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
|
package/dist/client/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../lib/client/index.ts"],"names":[],"mappings":";;;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../lib/client/index.ts"],"names":[],"mappings":";;;;;;;;;;;AAsDA,oBA2DC;AAYD,4BAuBC;AApJD,uCAAuC;AACvC,sCAA6D;AAU7D;;;;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,MAAM,MAAM,GAAG,MAAA,iBAAiB,CAAC,QAAQ,0CAAE,MAAM,CAAC;QAClD,IAAI,CAAC,MAAM,IAAI,MAAM,CAAC,IAAI,IAAI,CAAC,EAAE,CAAC;YAChC,OAAO,iBAAiB,CAAC,IAAI,CAAC;QAChC,CAAC;QAED,MAAM,MAAM,GAAG,CAAC,GAAG,iBAAiB,CAAC,IAAI,CAAC,CAAC;QAC3C,MAAM,UAAU,GAAG,MAAM,CAAC,IAAI,CAAC;QAE/B,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;;;;;;;;;GASG;AACH,SAAsB,QAAQ,CAC5B,IAAY,EACZ,YAAwC;;QAExC,MAAM,MAAM,GAAG,IAAA,sBAAa,GAAE,CAAC;QAE/B,+CAA+C;QAC/C,yEAAyE;QACzE,MAAM,QAAQ,GAAG,MAAM,IAAA,oBAAU,EAAqB,MAAM,CAAC,UAAU,kBACrE,KAAK,EAAE,EAAE,CAAC,EAAE,IAAI,EAAE,GAAG,EAAE,GAAG,EAAE,IACzB,YAAY,EACf,CAAC;QAEH,IAAI,CAAC,QAAQ,IAAI,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC;YAChC,OAAO,IAAI,CAAC;QACd,CAAC;QAED,0BAA0B;QAC1B,MAAM,EAAE,GAAG,QAAQ,CAAC,IAAI,CAAC,IAAI,CAC3B,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,EAAE,KAAK,IAAI,IAAI,GAAG,CAAC,KAAK,KAAK,QAAQ,CAAC,IAAI,EAAE,EAAE,CAAC,CAC7D,CAAC;QAEF,OAAO,EAAE,IAAI,IAAI,CAAC;IACpB,CAAC;CAAA"}
|
package/dist/client/request.d.ts
CHANGED
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
import { type FetchOptions } from 'ofetch';
|
|
2
2
|
/**
|
|
3
|
-
* Make an API request with
|
|
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
|
|
8
|
+
export declare function apiRequest<T>(url: string, options?: FetchOptions<'json', any>): Promise<T>;
|
package/dist/client/request.js
CHANGED
|
@@ -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
|
|
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 = {}
|
|
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
|
-
|
|
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":";;;;;;;;;;;
|
|
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"}
|
package/dist/config/index.js
CHANGED
|
@@ -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://
|
|
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
|
/**
|
package/dist/config/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../lib/config/index.ts"],"names":[],"mappings":";;;AAEA;;GAEG;AACU,QAAA,aAAa,GAAkB;IAC1C,UAAU,
|
|
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"}
|
package/dist/types/config.d.ts
CHANGED
|
@@ -4,25 +4,15 @@
|
|
|
4
4
|
export interface BlocketConfig {
|
|
5
5
|
/**
|
|
6
6
|
* Base URL for the Blocket API.
|
|
7
|
-
* @default 'https://
|
|
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.
|
package/dist/types/index.d.ts
CHANGED
|
@@ -1,95 +1,72 @@
|
|
|
1
1
|
export * from './config';
|
|
2
2
|
/**
|
|
3
|
-
*
|
|
3
|
+
* Blocket API response containing an array of ads with metadata.
|
|
4
4
|
*/
|
|
5
|
-
export
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
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
|
|
11
|
+
* Blocket API metadata containing pagination and search info.
|
|
18
12
|
*/
|
|
19
|
-
export interface
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
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
|
-
|
|
32
|
-
|
|
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
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
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
|
-
|
|
64
|
-
|
|
65
|
-
|
|
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
|
-
|
|
68
|
-
|
|
69
|
-
location: Array<{
|
|
57
|
+
ad_type: number;
|
|
58
|
+
labels: Array<{
|
|
70
59
|
id: string;
|
|
71
|
-
|
|
72
|
-
|
|
60
|
+
text: string;
|
|
61
|
+
type: 'PRIMARY' | 'SECONDARY' | string;
|
|
73
62
|
}>;
|
|
74
|
-
|
|
75
|
-
|
|
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
|
-
|
|
83
|
-
|
|
66
|
+
amount: number;
|
|
67
|
+
currency_code: string;
|
|
68
|
+
price_unit: string;
|
|
84
69
|
};
|
|
85
|
-
|
|
86
|
-
|
|
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
|
}
|
package/lib/client/index.ts
CHANGED
|
@@ -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.
|
|
78
|
-
!Array.isArray(firstPageResponse.
|
|
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?.
|
|
80
|
+
`Unexpected Blocket API response structure, expected array of ads, got: ${typeof firstPageResponse?.docs}`
|
|
82
81
|
);
|
|
83
82
|
}
|
|
84
83
|
|
|
85
|
-
|
|
86
|
-
|
|
84
|
+
const paging = firstPageResponse.metadata?.paging;
|
|
85
|
+
if (!paging || paging.last <= 1) {
|
|
86
|
+
return firstPageResponse.docs;
|
|
87
87
|
}
|
|
88
88
|
|
|
89
|
-
const allAds = [...firstPageResponse.
|
|
90
|
-
const totalPages =
|
|
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.
|
|
105
|
-
allAds.push(...response.
|
|
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
|
|
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
|
-
|
|
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 (!
|
|
139
|
+
if (!response || !response.docs) {
|
|
132
140
|
return null;
|
|
133
141
|
}
|
|
134
142
|
|
|
135
|
-
|
|
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
|
}
|
package/lib/client/request.ts
CHANGED
|
@@ -1,54 +1,32 @@
|
|
|
1
1
|
import { ofetch, type FetchOptions } from 'ofetch';
|
|
2
2
|
|
|
3
|
-
import {
|
|
4
|
-
import { getBaseConfig, logger } from '../config';
|
|
3
|
+
import { logger } from '../config';
|
|
5
4
|
|
|
6
5
|
/**
|
|
7
|
-
* Make an API request with
|
|
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
|
-
|
|
16
|
+
return await ofetch<T>(url, {
|
|
23
17
|
...options,
|
|
24
18
|
headers: {
|
|
25
|
-
'
|
|
26
|
-
|
|
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
|
-
'
|
|
45
|
-
`
|
|
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
|
}
|
package/lib/config/index.ts
CHANGED
|
@@ -4,11 +4,9 @@ import { BlocketQueryConfig, BlocketConfig } from '../types';
|
|
|
4
4
|
* Default global configuration.
|
|
5
5
|
*/
|
|
6
6
|
export const defaultConfig: BlocketConfig = {
|
|
7
|
-
apiBaseUrl:
|
|
8
|
-
|
|
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 };
|
package/lib/types/config.ts
CHANGED
|
@@ -4,25 +4,15 @@
|
|
|
4
4
|
export interface BlocketConfig {
|
|
5
5
|
/**
|
|
6
6
|
* Base URL for the Blocket API.
|
|
7
|
-
* @default 'https://
|
|
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
|
/**
|
package/lib/types/index.ts
CHANGED
|
@@ -1,99 +1,76 @@
|
|
|
1
1
|
export * from './config';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
|
-
*
|
|
4
|
+
* Blocket API response containing an array of ads with metadata.
|
|
5
5
|
*/
|
|
6
|
-
export
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
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
|
|
13
|
+
* Blocket API metadata containing pagination and search info.
|
|
21
14
|
*/
|
|
22
|
-
export interface
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
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
|
-
|
|
35
|
-
|
|
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
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
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
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
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
|
-
|
|
76
|
-
|
|
63
|
+
text: string;
|
|
64
|
+
type: 'PRIMARY' | 'SECONDARY' | string;
|
|
77
65
|
}>;
|
|
78
|
-
|
|
79
|
-
|
|
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
|
-
|
|
87
|
-
|
|
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
|
-
|
|
95
|
-
|
|
96
|
-
subject: string;
|
|
97
|
-
type: string;
|
|
98
|
-
zipcode: string;
|
|
73
|
+
distance: number;
|
|
74
|
+
trade_type: string;
|
|
99
75
|
}
|
|
76
|
+
|
package/package.json
CHANGED
package/dist/client/token.d.ts
DELETED
|
@@ -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>;
|
package/dist/client/token.js
DELETED
|
@@ -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
|
package/dist/client/token.js.map
DELETED
|
@@ -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"}
|
package/lib/client/token.ts
DELETED
|
@@ -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
|
-
};
|