lacspace-leads 0.2.0 → 0.3.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 +86 -14
- package/dist/cli.js +426 -49
- package/dist/lib.cjs +355 -26
- package/dist/lib.d.cts +140 -6
- package/dist/lib.d.ts +140 -6
- package/dist/lib.js +344 -26
- package/package.json +8 -4
package/dist/lib.d.cts
CHANGED
|
@@ -1,9 +1,17 @@
|
|
|
1
1
|
/** The fields a {@link Lead} can carry — request any subset via `fields`. */
|
|
2
|
-
type LeadField = "name" | "category" | "rating" | "reviews" | "priceLevel" | "address" | "phone" | "website" | "email" | "facebook" | "instagram" | "whatsapp" | "plusCode" | "latitude" | "longitude" | "hours" | "mapsUrl";
|
|
2
|
+
type LeadField = "name" | "category" | "rating" | "reviews" | "priceLevel" | "address" | "phone" | "website" | "email" | "facebook" | "instagram" | "whatsapp" | "linkedin" | "twitter" | "youtube" | "tiktok" | "telegram" | "plusCode" | "latitude" | "longitude" | "hours" | "mapsUrl";
|
|
3
3
|
/** Every field, in a sensible column order for exports. */
|
|
4
4
|
declare const ALL_FIELDS: LeadField[];
|
|
5
5
|
/** Fields that require visiting the business website (via `enrich`). */
|
|
6
6
|
declare const ENRICHED_FIELDS: LeadField[];
|
|
7
|
+
/** Named field bundles for common jobs — pass via `preset` / `--preset`. */
|
|
8
|
+
declare const FIELD_PRESETS: Record<string, LeadField[]>;
|
|
9
|
+
/**
|
|
10
|
+
* Fields collected by default — everything Google Maps shows directly, i.e.
|
|
11
|
+
* {@link ALL_FIELDS} minus the {@link ENRICHED_FIELDS} that need a website visit.
|
|
12
|
+
* Ask for the enriched ones explicitly (or via `enrich`) to opt into that work.
|
|
13
|
+
*/
|
|
14
|
+
declare const DEFAULT_FIELDS: LeadField[];
|
|
7
15
|
/** A single collected business lead. Every field is optional — Maps listings vary. */
|
|
8
16
|
interface Lead {
|
|
9
17
|
name?: string;
|
|
@@ -25,6 +33,16 @@ interface Lead {
|
|
|
25
33
|
instagram?: string;
|
|
26
34
|
/** WhatsApp number/link, from the website (needs enrichment). */
|
|
27
35
|
whatsapp?: string;
|
|
36
|
+
/** LinkedIn company/profile URL, from the website (needs enrichment). */
|
|
37
|
+
linkedin?: string;
|
|
38
|
+
/** Twitter / X URL, from the website (needs enrichment). */
|
|
39
|
+
twitter?: string;
|
|
40
|
+
/** YouTube channel URL, from the website (needs enrichment). */
|
|
41
|
+
youtube?: string;
|
|
42
|
+
/** TikTok URL, from the website (needs enrichment). */
|
|
43
|
+
tiktok?: string;
|
|
44
|
+
/** Telegram link, from the website (needs enrichment). */
|
|
45
|
+
telegram?: string;
|
|
28
46
|
/** Google Plus Code, when shown. */
|
|
29
47
|
plusCode?: string;
|
|
30
48
|
/** Latitude, parsed from the listing's Maps URL. */
|
|
@@ -50,7 +68,9 @@ interface LeadFilters {
|
|
|
50
68
|
hasEmail?: boolean;
|
|
51
69
|
}
|
|
52
70
|
/** Output formats the tool can write. */
|
|
53
|
-
type OutputFormat = "json" | "csv" | "xlsx";
|
|
71
|
+
type OutputFormat = "json" | "ndjson" | "csv" | "xlsx";
|
|
72
|
+
/** How to sort collected leads before export. */
|
|
73
|
+
type SortKey$1 = "rating" | "reviews" | "name" | "priceLevel";
|
|
54
74
|
/** Options for a lead search. */
|
|
55
75
|
interface SearchOptions {
|
|
56
76
|
/** City, e.g. "Kathmandu". */
|
|
@@ -85,6 +105,27 @@ interface SearchOptions {
|
|
|
85
105
|
filters?: LeadFilters;
|
|
86
106
|
/** Drop duplicate leads by this key. Default "website" when present else "name". */
|
|
87
107
|
dedupe?: "website" | "phone" | "name" | "none";
|
|
108
|
+
/** Sort the results by this key before returning. */
|
|
109
|
+
sort?: SortKey$1;
|
|
110
|
+
/** Sort direction. Defaults to "desc" for numbers, "asc" for name. */
|
|
111
|
+
sortDir?: "asc" | "desc";
|
|
112
|
+
/**
|
|
113
|
+
* Normalise phone numbers to E.164 using this default country — an ISO-2 code
|
|
114
|
+
* (`"NP"`, `"US"`) or a raw calling code (`"977"`). Best-effort; numbers that
|
|
115
|
+
* can't be parsed are left as-is.
|
|
116
|
+
*/
|
|
117
|
+
country?: string;
|
|
118
|
+
/**
|
|
119
|
+
* Tidy website URLs — unwrap Google redirects and strip tracking params.
|
|
120
|
+
* Default true.
|
|
121
|
+
*/
|
|
122
|
+
cleanUrls?: boolean;
|
|
123
|
+
/** How many websites to enrich in parallel. Default 3. */
|
|
124
|
+
concurrency?: number;
|
|
125
|
+
/** Browser/UI locale, e.g. "en-US", "ne-NP". Default "en-US". */
|
|
126
|
+
locale?: string;
|
|
127
|
+
/** Google region bias (ccTLD-style), e.g. "np", "us". Sets Maps `gl`. */
|
|
128
|
+
region?: string;
|
|
88
129
|
/** Stop collecting after this many milliseconds (best-effort). */
|
|
89
130
|
maxMs?: number;
|
|
90
131
|
/** Called with a short progress message as the search runs. */
|
|
@@ -122,6 +163,32 @@ declare function parseLatLng(url: string): {
|
|
|
122
163
|
*/
|
|
123
164
|
declare function scrapeLeads(opts: SearchOptions): Promise<Lead[]>;
|
|
124
165
|
|
|
166
|
+
/** One sub-search in a batch. */
|
|
167
|
+
interface BatchQuery {
|
|
168
|
+
type?: string;
|
|
169
|
+
city?: string;
|
|
170
|
+
area?: string;
|
|
171
|
+
query?: string;
|
|
172
|
+
}
|
|
173
|
+
/**
|
|
174
|
+
* Run each `{type, city, area}` search in turn and merge the results, applying
|
|
175
|
+
* a single cross-search dedupe and sort at the end. Per-search `limit` is the
|
|
176
|
+
* cap for *each* sub-search; `opts.total`, when set, caps the merged list.
|
|
177
|
+
*
|
|
178
|
+
* Filtering and sorting are applied once, globally, here — so pass them via
|
|
179
|
+
* `opts` rather than relying on the per-search pass.
|
|
180
|
+
*/
|
|
181
|
+
declare function searchLeadsBatch(queries: BatchQuery[], opts?: Omit<SearchOptions, "type" | "city" | "area" | "query"> & {
|
|
182
|
+
total?: number;
|
|
183
|
+
}): Promise<Lead[]>;
|
|
184
|
+
/**
|
|
185
|
+
* Convenience wrapper: expand a single request with comma-separated
|
|
186
|
+
* `type`/`city`/`area` into its cross-product and run it as a batch.
|
|
187
|
+
*/
|
|
188
|
+
declare function searchLeadsMulti(opts: SearchOptions & {
|
|
189
|
+
total?: number;
|
|
190
|
+
}): Promise<Lead[]>;
|
|
191
|
+
|
|
125
192
|
/** Project leads onto exactly the requested fields, in order, as header-keyed rows. */
|
|
126
193
|
declare function toRows(leads: Lead[], fields?: LeadField[]): Record<string, string | number>[];
|
|
127
194
|
/** Serialize leads to a UTF-8 string or bytes in the chosen format. */
|
|
@@ -142,8 +209,32 @@ declare function composeQuery(opts: {
|
|
|
142
209
|
area?: string;
|
|
143
210
|
city?: string;
|
|
144
211
|
}): string;
|
|
145
|
-
/**
|
|
146
|
-
|
|
212
|
+
/**
|
|
213
|
+
* The Google Maps search URL for a query. `hl` (interface language) keeps the
|
|
214
|
+
* scraped aria-labels predictable; `gl` biases results to a region.
|
|
215
|
+
*/
|
|
216
|
+
declare function mapsSearchUrl(query: string, opts?: {
|
|
217
|
+
hl?: string;
|
|
218
|
+
gl?: string;
|
|
219
|
+
}): string;
|
|
220
|
+
/**
|
|
221
|
+
* Expand a possibly-multi search request into individual `{type, city, area}`
|
|
222
|
+
* queries — the cross-product of comma-separated types × cities × areas. An
|
|
223
|
+
* explicit `query` short-circuits to a single verbatim search. Used for batch.
|
|
224
|
+
*/
|
|
225
|
+
declare function expandQueries(opts: {
|
|
226
|
+
type?: string;
|
|
227
|
+
city?: string;
|
|
228
|
+
area?: string;
|
|
229
|
+
query?: string;
|
|
230
|
+
}): {
|
|
231
|
+
type?: string;
|
|
232
|
+
city?: string;
|
|
233
|
+
area?: string;
|
|
234
|
+
query?: string;
|
|
235
|
+
}[];
|
|
236
|
+
/** Resolve a preset name to its field list, case-insensitively. */
|
|
237
|
+
declare function resolvePreset(name?: string): LeadField[] | undefined;
|
|
147
238
|
/**
|
|
148
239
|
* Normalise a fields request (array or comma string) into known {@link LeadField}s
|
|
149
240
|
* in canonical order, de-duplicated. Unknown names are ignored; an empty result
|
|
@@ -161,6 +252,41 @@ declare function filterLeads(leads: Lead[], filters?: LeadFilters): Lead[];
|
|
|
161
252
|
*/
|
|
162
253
|
declare function dedupeLeads(leads: Lead[], by?: NonNullable<SearchOptions["dedupe"]>): Lead[];
|
|
163
254
|
|
|
255
|
+
/**
|
|
256
|
+
* Pure data-cleaning helpers — website tidy-up, best-effort E.164 phone
|
|
257
|
+
* normalisation, and lead sorting. All exported so they can be unit-tested and
|
|
258
|
+
* reused; none touch the network or the disk.
|
|
259
|
+
*/
|
|
260
|
+
|
|
261
|
+
/**
|
|
262
|
+
* Tidy a website URL: unwrap a Google `/url?q=…` redirect, drop tracking query
|
|
263
|
+
* params (utm_*, fbclid, gclid…) and any fragment, and lower-case the host.
|
|
264
|
+
* Returns `undefined` for empty input, and the original string if it can't be
|
|
265
|
+
* parsed as a URL. Pure.
|
|
266
|
+
*/
|
|
267
|
+
declare function cleanWebsite(url?: string): string | undefined;
|
|
268
|
+
/**
|
|
269
|
+
* ISO-3166 alpha-2 → E.164 country calling code, for a curated set of common
|
|
270
|
+
* markets. Extend as needed; unknown codes fall through to best-effort.
|
|
271
|
+
*/
|
|
272
|
+
declare const CALLING_CODES: Record<string, string>;
|
|
273
|
+
/** Resolve a country argument (ISO-2 code or a raw calling code) to digits. */
|
|
274
|
+
declare function callingCode(country?: string): string | undefined;
|
|
275
|
+
/**
|
|
276
|
+
* Best-effort E.164 normalisation of a phone string given a default country
|
|
277
|
+
* (an ISO-2 code like `"NP"` or a calling code like `"977"`). Numbers that
|
|
278
|
+
* already start with `+` are kept as international. When the result isn't a
|
|
279
|
+
* plausible 8–15-digit number, the original string is returned unchanged. Pure.
|
|
280
|
+
*/
|
|
281
|
+
declare function normalizePhone(raw?: string, country?: string): string | undefined;
|
|
282
|
+
/** Keys a lead list can be sorted by. */
|
|
283
|
+
type SortKey = "rating" | "reviews" | "name" | "priceLevel";
|
|
284
|
+
/**
|
|
285
|
+
* Sort leads by a key, missing values always last. Stable, pure, new array.
|
|
286
|
+
* `dir` defaults to descending for numeric keys and ascending for `name`.
|
|
287
|
+
*/
|
|
288
|
+
declare function sortLeads(leads: Lead[], by?: SortKey, dir?: "asc" | "desc"): Lead[];
|
|
289
|
+
|
|
164
290
|
/**
|
|
165
291
|
* Website enrichment — visit a business's site and pull an email + social
|
|
166
292
|
* links. Uses global `fetch` (Node 20+); every network call is guarded so a
|
|
@@ -172,10 +298,18 @@ interface Contacts {
|
|
|
172
298
|
facebook?: string;
|
|
173
299
|
instagram?: string;
|
|
174
300
|
whatsapp?: string;
|
|
301
|
+
linkedin?: string;
|
|
302
|
+
twitter?: string;
|
|
303
|
+
youtube?: string;
|
|
304
|
+
tiktok?: string;
|
|
305
|
+
telegram?: string;
|
|
175
306
|
}
|
|
176
307
|
/** Extract the best contact email from HTML, or `undefined`. Pure. */
|
|
177
308
|
declare function extractEmails(html: string): string | undefined;
|
|
178
|
-
/**
|
|
309
|
+
/**
|
|
310
|
+
* Extract social links (Facebook, Instagram, WhatsApp, LinkedIn, Twitter/X,
|
|
311
|
+
* YouTube, TikTok, Telegram) from HTML. Skips share/intent/widget links. Pure.
|
|
312
|
+
*/
|
|
179
313
|
declare function extractSocials(html: string): Omit<Contacts, "email">;
|
|
180
314
|
/**
|
|
181
315
|
* Fetch a website (home page, then a /contact page if needed) and pull an email
|
|
@@ -212,4 +346,4 @@ declare function convertFile(input: string, opts?: {
|
|
|
212
346
|
count: number;
|
|
213
347
|
}>;
|
|
214
348
|
|
|
215
|
-
export { ALL_FIELDS, type Contacts, type DataRow, ENRICHED_FIELDS, type Lead, type LeadField, type LeadFilters, LeadsError, type OutputFormat, type SearchOptions, columnsOf, composeQuery, convertFile, dedupeLeads, defaultFilename, detectFormat, enrichContacts, extractEmails, extractSocials, filterLeads, mapsSearchUrl, normalizeFields, parseLatLng, parseRating, parseReviewCount, readRows, scrapeLeads, scrapeLeads as searchLeads, serialize, serializeRows, toRows };
|
|
349
|
+
export { ALL_FIELDS, type BatchQuery, CALLING_CODES, type Contacts, DEFAULT_FIELDS, type DataRow, ENRICHED_FIELDS, FIELD_PRESETS, type Lead, type LeadField, type LeadFilters, LeadsError, type OutputFormat, type SearchOptions, type SortKey$1 as SortKey, callingCode, cleanWebsite, columnsOf, composeQuery, convertFile, dedupeLeads, defaultFilename, detectFormat, enrichContacts, expandQueries, extractEmails, extractSocials, filterLeads, mapsSearchUrl, normalizeFields, normalizePhone, parseLatLng, parseRating, parseReviewCount, readRows, resolvePreset, scrapeLeads, scrapeLeads as searchLeads, searchLeadsBatch, searchLeadsMulti, serialize, serializeRows, sortLeads, toRows };
|
package/dist/lib.d.ts
CHANGED
|
@@ -1,9 +1,17 @@
|
|
|
1
1
|
/** The fields a {@link Lead} can carry — request any subset via `fields`. */
|
|
2
|
-
type LeadField = "name" | "category" | "rating" | "reviews" | "priceLevel" | "address" | "phone" | "website" | "email" | "facebook" | "instagram" | "whatsapp" | "plusCode" | "latitude" | "longitude" | "hours" | "mapsUrl";
|
|
2
|
+
type LeadField = "name" | "category" | "rating" | "reviews" | "priceLevel" | "address" | "phone" | "website" | "email" | "facebook" | "instagram" | "whatsapp" | "linkedin" | "twitter" | "youtube" | "tiktok" | "telegram" | "plusCode" | "latitude" | "longitude" | "hours" | "mapsUrl";
|
|
3
3
|
/** Every field, in a sensible column order for exports. */
|
|
4
4
|
declare const ALL_FIELDS: LeadField[];
|
|
5
5
|
/** Fields that require visiting the business website (via `enrich`). */
|
|
6
6
|
declare const ENRICHED_FIELDS: LeadField[];
|
|
7
|
+
/** Named field bundles for common jobs — pass via `preset` / `--preset`. */
|
|
8
|
+
declare const FIELD_PRESETS: Record<string, LeadField[]>;
|
|
9
|
+
/**
|
|
10
|
+
* Fields collected by default — everything Google Maps shows directly, i.e.
|
|
11
|
+
* {@link ALL_FIELDS} minus the {@link ENRICHED_FIELDS} that need a website visit.
|
|
12
|
+
* Ask for the enriched ones explicitly (or via `enrich`) to opt into that work.
|
|
13
|
+
*/
|
|
14
|
+
declare const DEFAULT_FIELDS: LeadField[];
|
|
7
15
|
/** A single collected business lead. Every field is optional — Maps listings vary. */
|
|
8
16
|
interface Lead {
|
|
9
17
|
name?: string;
|
|
@@ -25,6 +33,16 @@ interface Lead {
|
|
|
25
33
|
instagram?: string;
|
|
26
34
|
/** WhatsApp number/link, from the website (needs enrichment). */
|
|
27
35
|
whatsapp?: string;
|
|
36
|
+
/** LinkedIn company/profile URL, from the website (needs enrichment). */
|
|
37
|
+
linkedin?: string;
|
|
38
|
+
/** Twitter / X URL, from the website (needs enrichment). */
|
|
39
|
+
twitter?: string;
|
|
40
|
+
/** YouTube channel URL, from the website (needs enrichment). */
|
|
41
|
+
youtube?: string;
|
|
42
|
+
/** TikTok URL, from the website (needs enrichment). */
|
|
43
|
+
tiktok?: string;
|
|
44
|
+
/** Telegram link, from the website (needs enrichment). */
|
|
45
|
+
telegram?: string;
|
|
28
46
|
/** Google Plus Code, when shown. */
|
|
29
47
|
plusCode?: string;
|
|
30
48
|
/** Latitude, parsed from the listing's Maps URL. */
|
|
@@ -50,7 +68,9 @@ interface LeadFilters {
|
|
|
50
68
|
hasEmail?: boolean;
|
|
51
69
|
}
|
|
52
70
|
/** Output formats the tool can write. */
|
|
53
|
-
type OutputFormat = "json" | "csv" | "xlsx";
|
|
71
|
+
type OutputFormat = "json" | "ndjson" | "csv" | "xlsx";
|
|
72
|
+
/** How to sort collected leads before export. */
|
|
73
|
+
type SortKey$1 = "rating" | "reviews" | "name" | "priceLevel";
|
|
54
74
|
/** Options for a lead search. */
|
|
55
75
|
interface SearchOptions {
|
|
56
76
|
/** City, e.g. "Kathmandu". */
|
|
@@ -85,6 +105,27 @@ interface SearchOptions {
|
|
|
85
105
|
filters?: LeadFilters;
|
|
86
106
|
/** Drop duplicate leads by this key. Default "website" when present else "name". */
|
|
87
107
|
dedupe?: "website" | "phone" | "name" | "none";
|
|
108
|
+
/** Sort the results by this key before returning. */
|
|
109
|
+
sort?: SortKey$1;
|
|
110
|
+
/** Sort direction. Defaults to "desc" for numbers, "asc" for name. */
|
|
111
|
+
sortDir?: "asc" | "desc";
|
|
112
|
+
/**
|
|
113
|
+
* Normalise phone numbers to E.164 using this default country — an ISO-2 code
|
|
114
|
+
* (`"NP"`, `"US"`) or a raw calling code (`"977"`). Best-effort; numbers that
|
|
115
|
+
* can't be parsed are left as-is.
|
|
116
|
+
*/
|
|
117
|
+
country?: string;
|
|
118
|
+
/**
|
|
119
|
+
* Tidy website URLs — unwrap Google redirects and strip tracking params.
|
|
120
|
+
* Default true.
|
|
121
|
+
*/
|
|
122
|
+
cleanUrls?: boolean;
|
|
123
|
+
/** How many websites to enrich in parallel. Default 3. */
|
|
124
|
+
concurrency?: number;
|
|
125
|
+
/** Browser/UI locale, e.g. "en-US", "ne-NP". Default "en-US". */
|
|
126
|
+
locale?: string;
|
|
127
|
+
/** Google region bias (ccTLD-style), e.g. "np", "us". Sets Maps `gl`. */
|
|
128
|
+
region?: string;
|
|
88
129
|
/** Stop collecting after this many milliseconds (best-effort). */
|
|
89
130
|
maxMs?: number;
|
|
90
131
|
/** Called with a short progress message as the search runs. */
|
|
@@ -122,6 +163,32 @@ declare function parseLatLng(url: string): {
|
|
|
122
163
|
*/
|
|
123
164
|
declare function scrapeLeads(opts: SearchOptions): Promise<Lead[]>;
|
|
124
165
|
|
|
166
|
+
/** One sub-search in a batch. */
|
|
167
|
+
interface BatchQuery {
|
|
168
|
+
type?: string;
|
|
169
|
+
city?: string;
|
|
170
|
+
area?: string;
|
|
171
|
+
query?: string;
|
|
172
|
+
}
|
|
173
|
+
/**
|
|
174
|
+
* Run each `{type, city, area}` search in turn and merge the results, applying
|
|
175
|
+
* a single cross-search dedupe and sort at the end. Per-search `limit` is the
|
|
176
|
+
* cap for *each* sub-search; `opts.total`, when set, caps the merged list.
|
|
177
|
+
*
|
|
178
|
+
* Filtering and sorting are applied once, globally, here — so pass them via
|
|
179
|
+
* `opts` rather than relying on the per-search pass.
|
|
180
|
+
*/
|
|
181
|
+
declare function searchLeadsBatch(queries: BatchQuery[], opts?: Omit<SearchOptions, "type" | "city" | "area" | "query"> & {
|
|
182
|
+
total?: number;
|
|
183
|
+
}): Promise<Lead[]>;
|
|
184
|
+
/**
|
|
185
|
+
* Convenience wrapper: expand a single request with comma-separated
|
|
186
|
+
* `type`/`city`/`area` into its cross-product and run it as a batch.
|
|
187
|
+
*/
|
|
188
|
+
declare function searchLeadsMulti(opts: SearchOptions & {
|
|
189
|
+
total?: number;
|
|
190
|
+
}): Promise<Lead[]>;
|
|
191
|
+
|
|
125
192
|
/** Project leads onto exactly the requested fields, in order, as header-keyed rows. */
|
|
126
193
|
declare function toRows(leads: Lead[], fields?: LeadField[]): Record<string, string | number>[];
|
|
127
194
|
/** Serialize leads to a UTF-8 string or bytes in the chosen format. */
|
|
@@ -142,8 +209,32 @@ declare function composeQuery(opts: {
|
|
|
142
209
|
area?: string;
|
|
143
210
|
city?: string;
|
|
144
211
|
}): string;
|
|
145
|
-
/**
|
|
146
|
-
|
|
212
|
+
/**
|
|
213
|
+
* The Google Maps search URL for a query. `hl` (interface language) keeps the
|
|
214
|
+
* scraped aria-labels predictable; `gl` biases results to a region.
|
|
215
|
+
*/
|
|
216
|
+
declare function mapsSearchUrl(query: string, opts?: {
|
|
217
|
+
hl?: string;
|
|
218
|
+
gl?: string;
|
|
219
|
+
}): string;
|
|
220
|
+
/**
|
|
221
|
+
* Expand a possibly-multi search request into individual `{type, city, area}`
|
|
222
|
+
* queries — the cross-product of comma-separated types × cities × areas. An
|
|
223
|
+
* explicit `query` short-circuits to a single verbatim search. Used for batch.
|
|
224
|
+
*/
|
|
225
|
+
declare function expandQueries(opts: {
|
|
226
|
+
type?: string;
|
|
227
|
+
city?: string;
|
|
228
|
+
area?: string;
|
|
229
|
+
query?: string;
|
|
230
|
+
}): {
|
|
231
|
+
type?: string;
|
|
232
|
+
city?: string;
|
|
233
|
+
area?: string;
|
|
234
|
+
query?: string;
|
|
235
|
+
}[];
|
|
236
|
+
/** Resolve a preset name to its field list, case-insensitively. */
|
|
237
|
+
declare function resolvePreset(name?: string): LeadField[] | undefined;
|
|
147
238
|
/**
|
|
148
239
|
* Normalise a fields request (array or comma string) into known {@link LeadField}s
|
|
149
240
|
* in canonical order, de-duplicated. Unknown names are ignored; an empty result
|
|
@@ -161,6 +252,41 @@ declare function filterLeads(leads: Lead[], filters?: LeadFilters): Lead[];
|
|
|
161
252
|
*/
|
|
162
253
|
declare function dedupeLeads(leads: Lead[], by?: NonNullable<SearchOptions["dedupe"]>): Lead[];
|
|
163
254
|
|
|
255
|
+
/**
|
|
256
|
+
* Pure data-cleaning helpers — website tidy-up, best-effort E.164 phone
|
|
257
|
+
* normalisation, and lead sorting. All exported so they can be unit-tested and
|
|
258
|
+
* reused; none touch the network or the disk.
|
|
259
|
+
*/
|
|
260
|
+
|
|
261
|
+
/**
|
|
262
|
+
* Tidy a website URL: unwrap a Google `/url?q=…` redirect, drop tracking query
|
|
263
|
+
* params (utm_*, fbclid, gclid…) and any fragment, and lower-case the host.
|
|
264
|
+
* Returns `undefined` for empty input, and the original string if it can't be
|
|
265
|
+
* parsed as a URL. Pure.
|
|
266
|
+
*/
|
|
267
|
+
declare function cleanWebsite(url?: string): string | undefined;
|
|
268
|
+
/**
|
|
269
|
+
* ISO-3166 alpha-2 → E.164 country calling code, for a curated set of common
|
|
270
|
+
* markets. Extend as needed; unknown codes fall through to best-effort.
|
|
271
|
+
*/
|
|
272
|
+
declare const CALLING_CODES: Record<string, string>;
|
|
273
|
+
/** Resolve a country argument (ISO-2 code or a raw calling code) to digits. */
|
|
274
|
+
declare function callingCode(country?: string): string | undefined;
|
|
275
|
+
/**
|
|
276
|
+
* Best-effort E.164 normalisation of a phone string given a default country
|
|
277
|
+
* (an ISO-2 code like `"NP"` or a calling code like `"977"`). Numbers that
|
|
278
|
+
* already start with `+` are kept as international. When the result isn't a
|
|
279
|
+
* plausible 8–15-digit number, the original string is returned unchanged. Pure.
|
|
280
|
+
*/
|
|
281
|
+
declare function normalizePhone(raw?: string, country?: string): string | undefined;
|
|
282
|
+
/** Keys a lead list can be sorted by. */
|
|
283
|
+
type SortKey = "rating" | "reviews" | "name" | "priceLevel";
|
|
284
|
+
/**
|
|
285
|
+
* Sort leads by a key, missing values always last. Stable, pure, new array.
|
|
286
|
+
* `dir` defaults to descending for numeric keys and ascending for `name`.
|
|
287
|
+
*/
|
|
288
|
+
declare function sortLeads(leads: Lead[], by?: SortKey, dir?: "asc" | "desc"): Lead[];
|
|
289
|
+
|
|
164
290
|
/**
|
|
165
291
|
* Website enrichment — visit a business's site and pull an email + social
|
|
166
292
|
* links. Uses global `fetch` (Node 20+); every network call is guarded so a
|
|
@@ -172,10 +298,18 @@ interface Contacts {
|
|
|
172
298
|
facebook?: string;
|
|
173
299
|
instagram?: string;
|
|
174
300
|
whatsapp?: string;
|
|
301
|
+
linkedin?: string;
|
|
302
|
+
twitter?: string;
|
|
303
|
+
youtube?: string;
|
|
304
|
+
tiktok?: string;
|
|
305
|
+
telegram?: string;
|
|
175
306
|
}
|
|
176
307
|
/** Extract the best contact email from HTML, or `undefined`. Pure. */
|
|
177
308
|
declare function extractEmails(html: string): string | undefined;
|
|
178
|
-
/**
|
|
309
|
+
/**
|
|
310
|
+
* Extract social links (Facebook, Instagram, WhatsApp, LinkedIn, Twitter/X,
|
|
311
|
+
* YouTube, TikTok, Telegram) from HTML. Skips share/intent/widget links. Pure.
|
|
312
|
+
*/
|
|
179
313
|
declare function extractSocials(html: string): Omit<Contacts, "email">;
|
|
180
314
|
/**
|
|
181
315
|
* Fetch a website (home page, then a /contact page if needed) and pull an email
|
|
@@ -212,4 +346,4 @@ declare function convertFile(input: string, opts?: {
|
|
|
212
346
|
count: number;
|
|
213
347
|
}>;
|
|
214
348
|
|
|
215
|
-
export { ALL_FIELDS, type Contacts, type DataRow, ENRICHED_FIELDS, type Lead, type LeadField, type LeadFilters, LeadsError, type OutputFormat, type SearchOptions, columnsOf, composeQuery, convertFile, dedupeLeads, defaultFilename, detectFormat, enrichContacts, extractEmails, extractSocials, filterLeads, mapsSearchUrl, normalizeFields, parseLatLng, parseRating, parseReviewCount, readRows, scrapeLeads, scrapeLeads as searchLeads, serialize, serializeRows, toRows };
|
|
349
|
+
export { ALL_FIELDS, type BatchQuery, CALLING_CODES, type Contacts, DEFAULT_FIELDS, type DataRow, ENRICHED_FIELDS, FIELD_PRESETS, type Lead, type LeadField, type LeadFilters, LeadsError, type OutputFormat, type SearchOptions, type SortKey$1 as SortKey, callingCode, cleanWebsite, columnsOf, composeQuery, convertFile, dedupeLeads, defaultFilename, detectFormat, enrichContacts, expandQueries, extractEmails, extractSocials, filterLeads, mapsSearchUrl, normalizeFields, normalizePhone, parseLatLng, parseRating, parseReviewCount, readRows, resolvePreset, scrapeLeads, scrapeLeads as searchLeads, searchLeadsBatch, searchLeadsMulti, serialize, serializeRows, sortLeads, toRows };
|