blocket.js 1.1.2 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +7 -9
- package/dist/client/index.d.ts +2 -1
- package/dist/client/index.js +31 -5
- package/dist/client/index.js.map +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/types/index.d.ts +18 -6
- package/lib/client/index.ts +47 -7
- package/lib/index.ts +2 -1
- package/lib/types/index.ts +18 -6
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -14,6 +14,7 @@ blocket.js is a lightweight and easy-to-use npm package that provides a TypeScri
|
|
|
14
14
|
- **Configurable**: Global and per-request configuration options let you override API endpoints, logging preferences, retry attempts, and more.
|
|
15
15
|
- **TypeScript Support**: Fully typed interfaces for query parameters, API responses, and advertisements.
|
|
16
16
|
- **Robust Error Handling & Logging**: Automatic retries on token expiry with configurable logging to assist in debugging.
|
|
17
|
+
- **Automatic Pagination**: Seamlessly fetches all results across multiple pages without any additional configuration.
|
|
17
18
|
|
|
18
19
|
## Installation
|
|
19
20
|
|
|
@@ -40,8 +41,9 @@ import client from 'blocket.js';
|
|
|
40
41
|
|
|
41
42
|
(async () => {
|
|
42
43
|
try {
|
|
44
|
+
// This automatically fetches all results across all pages
|
|
43
45
|
const ads = await client.find({ query: 'macbook air' });
|
|
44
|
-
console.log(ads);
|
|
46
|
+
console.log(`Found ${ads.length} total listings`);
|
|
45
47
|
} catch (error) {
|
|
46
48
|
console.error('Error fetching ads:', error);
|
|
47
49
|
}
|
|
@@ -99,19 +101,19 @@ import client from 'blocket.js';
|
|
|
99
101
|
|
|
100
102
|
`client.find(query: BlocketQueryConfig, fetchOptions?: FetchOptions<'json', any>): Promise<BlocketAd[]>`
|
|
101
103
|
|
|
102
|
-
Searches for ads on Blocket based on the provided query parameters.
|
|
104
|
+
Searches for ads on Blocket based on the provided query parameters. Automatically handles pagination to return all matching listings across all pages.
|
|
103
105
|
|
|
104
106
|
- Parameters:
|
|
105
107
|
- `query`: An object conforming to the `BlocketQueryConfig` interface:
|
|
106
108
|
- `query` (string): The search query (e.g., `'macbook air'`).
|
|
107
|
-
- `limit` (number, optional): Maximum number of results to return (default: 20).
|
|
109
|
+
- `limit` (number, optional): Maximum number of results to return per page (default: 20).
|
|
108
110
|
- `sort` (string, optional): Sorting order (default: `'rel'`).
|
|
109
111
|
- `listingType` (string, optional): Listing type; `'s'` for selling, `'b'` for buying (default: `'s'`).
|
|
110
112
|
- `status` (string, optional): Ad status (`'active'` or `'inactive'`, default: `'active'`).
|
|
111
113
|
- `geolocation` (number, optional): Maximum distance in kilometers.
|
|
112
114
|
- `include` (string, optional): Additional filters or fields to include (e.g., 'extend_with_shipping').
|
|
113
115
|
- `fetchOptions` (optional): Additional options to pass to the underlying fetch request.
|
|
114
|
-
- Returns: A promise that resolves to an array of `BlocketAd` objects.
|
|
116
|
+
- Returns: A promise that resolves to an array of `BlocketAd` objects from all available pages.
|
|
115
117
|
|
|
116
118
|
`client.findById(adId: string, fetchOptions?: FetchOptions<'json', any>): Promise<BlocketAd>`
|
|
117
119
|
|
|
@@ -126,8 +128,4 @@ Retrieves a specific ad by its ID.
|
|
|
126
128
|
|
|
127
129
|
This project is licensed under the [MIT License](https://github.com/rutbergphilip/blocket.js/blob/main/LICENSE) – free for personal and commercial use.
|
|
128
130
|
|
|
129
|
-
If you find this project useful, crediting the author is greatly appreciated!
|
|
130
|
-
|
|
131
|
-
## Star History
|
|
132
|
-
|
|
133
|
-
[](https://star-history.com/#rutbergphilip/blocket.js&Date)
|
|
131
|
+
If you find this project useful, crediting the author and contributing to the project is greatly appreciated!
|
package/dist/client/index.d.ts
CHANGED
|
@@ -2,9 +2,10 @@ import type { FetchOptions } from 'ofetch';
|
|
|
2
2
|
import type { BlocketAd, BlocketQueryConfig } from '../types';
|
|
3
3
|
/**
|
|
4
4
|
* Find ads on Blocket based on query parameters.
|
|
5
|
+
* Automatically handles pagination if the API returns multiple pages of results.
|
|
5
6
|
* @param query Blocket query parameters.
|
|
6
7
|
* @param fetchOptions Additional fetch options.
|
|
7
|
-
* @returns Array of Blocket ads.
|
|
8
|
+
* @returns Array of Blocket ads from all available pages.
|
|
8
9
|
*/
|
|
9
10
|
export declare function find(query: BlocketQueryConfig, fetchOptions?: FetchOptions<'json', any>): Promise<BlocketAd[]>;
|
|
10
11
|
/**
|
package/dist/client/index.js
CHANGED
|
@@ -41,9 +41,10 @@ function remapQueryParams(params) {
|
|
|
41
41
|
}
|
|
42
42
|
/**
|
|
43
43
|
* Find ads on Blocket based on query parameters.
|
|
44
|
+
* Automatically handles pagination if the API returns multiple pages of results.
|
|
44
45
|
* @param query Blocket query parameters.
|
|
45
46
|
* @param fetchOptions Additional fetch options.
|
|
46
|
-
* @returns Array of Blocket ads.
|
|
47
|
+
* @returns Array of Blocket ads from all available pages.
|
|
47
48
|
*/
|
|
48
49
|
function find(query, fetchOptions) {
|
|
49
50
|
return __awaiter(this, void 0, void 0, function* () {
|
|
@@ -51,11 +52,36 @@ function find(query, fetchOptions) {
|
|
|
51
52
|
throw new Error('Query string is required');
|
|
52
53
|
const config = (0, config_1.getBaseConfig)();
|
|
53
54
|
const queryConfig = (0, config_1.createQueryConfig)(query);
|
|
54
|
-
const
|
|
55
|
-
|
|
56
|
-
|
|
55
|
+
const params = remapQueryParams(queryConfig);
|
|
56
|
+
const firstPageResponse = yield (0, request_1.apiRequest)(config.apiBaseUrl, Object.assign({ query: params }, fetchOptions));
|
|
57
|
+
if (!firstPageResponse ||
|
|
58
|
+
!firstPageResponse.data ||
|
|
59
|
+
!Array.isArray(firstPageResponse.data)) {
|
|
60
|
+
throw new Error(`Unexpected Blocket API response structure, expected array of ads, got: ${typeof (firstPageResponse === null || firstPageResponse === void 0 ? void 0 : firstPageResponse.data)}`);
|
|
57
61
|
}
|
|
58
|
-
|
|
62
|
+
if (firstPageResponse.total_page_count <= 1) {
|
|
63
|
+
return firstPageResponse.data;
|
|
64
|
+
}
|
|
65
|
+
const allAds = [...firstPageResponse.data];
|
|
66
|
+
const totalPages = firstPageResponse.total_page_count;
|
|
67
|
+
const pagePromises = [];
|
|
68
|
+
for (let page = 2; page <= totalPages; page++) {
|
|
69
|
+
Object.assign(params, {
|
|
70
|
+
page,
|
|
71
|
+
});
|
|
72
|
+
const pagePromise = (0, request_1.apiRequest)(config.apiBaseUrl, Object.assign({ query: params }, fetchOptions));
|
|
73
|
+
pagePromises.push(pagePromise);
|
|
74
|
+
}
|
|
75
|
+
const pageResponses = yield Promise.all(pagePromises);
|
|
76
|
+
for (const response of pageResponses) {
|
|
77
|
+
if (response && response.data && Array.isArray(response.data)) {
|
|
78
|
+
allAds.push(...response.data);
|
|
79
|
+
}
|
|
80
|
+
else {
|
|
81
|
+
throw new Error(`Unexpected Blocket API response structure in paginated results, expected array of ads`);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
return allAds;
|
|
59
85
|
});
|
|
60
86
|
}
|
|
61
87
|
/**
|
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":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -3,4 +3,5 @@ export default client;
|
|
|
3
3
|
import { configure } from './config';
|
|
4
4
|
export { configure };
|
|
5
5
|
import type { BlocketQueryConfig } from './types/config';
|
|
6
|
-
|
|
6
|
+
import type { BlocketAd } from './types';
|
|
7
|
+
export type { BlocketQueryConfig, BlocketAd };
|
package/dist/types/index.d.ts
CHANGED
|
@@ -7,18 +7,30 @@ export type BlocketAccessToken = {
|
|
|
7
7
|
isLoggedIn: false;
|
|
8
8
|
bearerToken: string;
|
|
9
9
|
};
|
|
10
|
-
/**
|
|
11
|
-
* Blocket API response containing an array of ads.
|
|
12
|
-
*/
|
|
13
|
-
export interface BlocketAdSearchResponse {
|
|
14
|
-
data: BlocketAd[];
|
|
15
|
-
}
|
|
16
10
|
/**
|
|
17
11
|
* Blocket API response containing a single ad.
|
|
18
12
|
*/
|
|
19
13
|
export interface BlocketAdResponse {
|
|
20
14
|
data: BlocketAd;
|
|
21
15
|
}
|
|
16
|
+
/**
|
|
17
|
+
* Blocket API response containing an array of ads with additional metadata.
|
|
18
|
+
*/
|
|
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;
|
|
30
|
+
title: string;
|
|
31
|
+
total_count: number;
|
|
32
|
+
total_page_count: number;
|
|
33
|
+
}
|
|
22
34
|
/**
|
|
23
35
|
* Blocket advertisement object.
|
|
24
36
|
*/
|
package/lib/client/index.ts
CHANGED
|
@@ -6,8 +6,8 @@ import type {
|
|
|
6
6
|
BlocketQueryParamsNative,
|
|
7
7
|
BlocketAd,
|
|
8
8
|
BlocketAdResponse,
|
|
9
|
-
BlocketAdSearchResponse,
|
|
10
9
|
BlocketQueryConfig,
|
|
10
|
+
BlocketApiResponse,
|
|
11
11
|
} from '../types';
|
|
12
12
|
|
|
13
13
|
/**
|
|
@@ -47,9 +47,10 @@ function remapQueryParams(
|
|
|
47
47
|
|
|
48
48
|
/**
|
|
49
49
|
* Find ads on Blocket based on query parameters.
|
|
50
|
+
* Automatically handles pagination if the API returns multiple pages of results.
|
|
50
51
|
* @param query Blocket query parameters.
|
|
51
52
|
* @param fetchOptions Additional fetch options.
|
|
52
|
-
* @returns Array of Blocket ads.
|
|
53
|
+
* @returns Array of Blocket ads from all available pages.
|
|
53
54
|
*/
|
|
54
55
|
export async function find(
|
|
55
56
|
query: BlocketQueryConfig,
|
|
@@ -60,21 +61,60 @@ export async function find(
|
|
|
60
61
|
const config = getBaseConfig();
|
|
61
62
|
const queryConfig = createQueryConfig(query);
|
|
62
63
|
|
|
63
|
-
const
|
|
64
|
+
const params = remapQueryParams(queryConfig);
|
|
65
|
+
|
|
66
|
+
const firstPageResponse = await apiRequest<BlocketApiResponse>(
|
|
64
67
|
config.apiBaseUrl,
|
|
65
68
|
{
|
|
66
|
-
query:
|
|
69
|
+
query: params,
|
|
67
70
|
...fetchOptions,
|
|
68
71
|
}
|
|
69
72
|
);
|
|
70
73
|
|
|
71
|
-
if (
|
|
74
|
+
if (
|
|
75
|
+
!firstPageResponse ||
|
|
76
|
+
!firstPageResponse.data ||
|
|
77
|
+
!Array.isArray(firstPageResponse.data)
|
|
78
|
+
) {
|
|
72
79
|
throw new Error(
|
|
73
|
-
`Unexpected Blocket API response structure, expected array of ads, got: ${typeof
|
|
80
|
+
`Unexpected Blocket API response structure, expected array of ads, got: ${typeof firstPageResponse?.data}`
|
|
74
81
|
);
|
|
75
82
|
}
|
|
76
83
|
|
|
77
|
-
|
|
84
|
+
if (firstPageResponse.total_page_count <= 1) {
|
|
85
|
+
return firstPageResponse.data;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
const allAds = [...firstPageResponse.data];
|
|
89
|
+
const totalPages = firstPageResponse.total_page_count;
|
|
90
|
+
|
|
91
|
+
const pagePromises = [];
|
|
92
|
+
for (let page = 2; page <= totalPages; page++) {
|
|
93
|
+
Object.assign(params, {
|
|
94
|
+
page,
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
const pagePromise = apiRequest<BlocketApiResponse>(config.apiBaseUrl, {
|
|
98
|
+
query: params,
|
|
99
|
+
...fetchOptions,
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
pagePromises.push(pagePromise);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
const pageResponses = await Promise.all(pagePromises);
|
|
106
|
+
|
|
107
|
+
for (const response of pageResponses) {
|
|
108
|
+
if (response && response.data && Array.isArray(response.data)) {
|
|
109
|
+
allAds.push(...response.data);
|
|
110
|
+
} else {
|
|
111
|
+
throw new Error(
|
|
112
|
+
`Unexpected Blocket API response structure in paginated results, expected array of ads`
|
|
113
|
+
);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
return allAds;
|
|
78
118
|
}
|
|
79
119
|
|
|
80
120
|
/**
|
package/lib/index.ts
CHANGED
package/lib/types/index.ts
CHANGED
|
@@ -10,17 +10,29 @@ export type BlocketAccessToken = {
|
|
|
10
10
|
};
|
|
11
11
|
|
|
12
12
|
/**
|
|
13
|
-
* Blocket API response containing
|
|
13
|
+
* Blocket API response containing a single ad.
|
|
14
14
|
*/
|
|
15
|
-
export interface
|
|
16
|
-
data: BlocketAd
|
|
15
|
+
export interface BlocketAdResponse {
|
|
16
|
+
data: BlocketAd;
|
|
17
17
|
}
|
|
18
18
|
|
|
19
19
|
/**
|
|
20
|
-
* Blocket API response containing
|
|
20
|
+
* Blocket API response containing an array of ads with additional metadata.
|
|
21
21
|
*/
|
|
22
|
-
export interface
|
|
23
|
-
data: BlocketAd;
|
|
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;
|
|
33
|
+
title: string;
|
|
34
|
+
total_count: number;
|
|
35
|
+
total_page_count: number;
|
|
24
36
|
}
|
|
25
37
|
|
|
26
38
|
/**
|