ls-test-mcp 0.0.1
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/LICENSE +201 -0
- package/README.md +103 -0
- package/auth.d.mts +6 -0
- package/auth.d.mts.map +1 -0
- package/auth.d.ts +6 -0
- package/auth.d.ts.map +1 -0
- package/auth.js +37 -0
- package/auth.js.map +1 -0
- package/auth.mjs +32 -0
- package/auth.mjs.map +1 -0
- package/code-tool-paths.cjs +8 -0
- package/code-tool-paths.cjs.map +1 -0
- package/code-tool-paths.d.cts +2 -0
- package/code-tool-paths.d.cts.map +1 -0
- package/code-tool-types.d.mts +14 -0
- package/code-tool-types.d.mts.map +1 -0
- package/code-tool-types.d.ts +14 -0
- package/code-tool-types.d.ts.map +1 -0
- package/code-tool-types.js +4 -0
- package/code-tool-types.js.map +1 -0
- package/code-tool-types.mjs +3 -0
- package/code-tool-types.mjs.map +1 -0
- package/code-tool-worker.d.mts +5 -0
- package/code-tool-worker.d.mts.map +1 -0
- package/code-tool-worker.d.ts +5 -0
- package/code-tool-worker.d.ts.map +1 -0
- package/code-tool-worker.js +279 -0
- package/code-tool-worker.js.map +1 -0
- package/code-tool-worker.mjs +241 -0
- package/code-tool-worker.mjs.map +1 -0
- package/code-tool.d.mts +21 -0
- package/code-tool.d.mts.map +1 -0
- package/code-tool.d.ts +21 -0
- package/code-tool.d.ts.map +1 -0
- package/code-tool.js +291 -0
- package/code-tool.js.map +1 -0
- package/code-tool.mjs +255 -0
- package/code-tool.mjs.map +1 -0
- package/docs-search-tool.d.mts +59 -0
- package/docs-search-tool.d.mts.map +1 -0
- package/docs-search-tool.d.ts +59 -0
- package/docs-search-tool.d.ts.map +1 -0
- package/docs-search-tool.js +64 -0
- package/docs-search-tool.js.map +1 -0
- package/docs-search-tool.mjs +59 -0
- package/docs-search-tool.mjs.map +1 -0
- package/http.d.mts +12 -0
- package/http.d.mts.map +1 -0
- package/http.d.ts +12 -0
- package/http.d.ts.map +1 -0
- package/http.js +190 -0
- package/http.js.map +1 -0
- package/http.mjs +182 -0
- package/http.mjs.map +1 -0
- package/index.d.mts +3 -0
- package/index.d.mts.map +1 -0
- package/index.d.ts +3 -0
- package/index.d.ts.map +1 -0
- package/index.js +60 -0
- package/index.js.map +1 -0
- package/index.mjs +58 -0
- package/index.mjs.map +1 -0
- package/instructions.d.mts +5 -0
- package/instructions.d.mts.map +1 -0
- package/instructions.d.ts +5 -0
- package/instructions.d.ts.map +1 -0
- package/instructions.js +45 -0
- package/instructions.js.map +1 -0
- package/instructions.mjs +39 -0
- package/instructions.mjs.map +1 -0
- package/local-docs-search.d.mts +28 -0
- package/local-docs-search.d.mts.map +1 -0
- package/local-docs-search.d.ts +28 -0
- package/local-docs-search.d.ts.map +1 -0
- package/local-docs-search.js +654 -0
- package/local-docs-search.js.map +1 -0
- package/local-docs-search.mjs +614 -0
- package/local-docs-search.mjs.map +1 -0
- package/logger.d.mts +7 -0
- package/logger.d.mts.map +1 -0
- package/logger.d.ts +7 -0
- package/logger.d.ts.map +1 -0
- package/logger.js +29 -0
- package/logger.js.map +1 -0
- package/logger.mjs +22 -0
- package/logger.mjs.map +1 -0
- package/methods.d.mts +10 -0
- package/methods.d.mts.map +1 -0
- package/methods.d.ts +10 -0
- package/methods.d.ts.map +1 -0
- package/methods.js +143 -0
- package/methods.js.map +1 -0
- package/methods.mjs +139 -0
- package/methods.mjs.map +1 -0
- package/options.d.mts +23 -0
- package/options.d.mts.map +1 -0
- package/options.d.ts +23 -0
- package/options.d.ts.map +1 -0
- package/options.js +141 -0
- package/options.js.map +1 -0
- package/options.mjs +134 -0
- package/options.mjs.map +1 -0
- package/package.json +235 -0
- package/server.d.mts +38 -0
- package/server.d.mts.map +1 -0
- package/server.d.ts +38 -0
- package/server.d.ts.map +1 -0
- package/server.js +170 -0
- package/server.js.map +1 -0
- package/server.mjs +160 -0
- package/server.mjs.map +1 -0
- package/src/auth.ts +42 -0
- package/src/code-tool-paths.cts +5 -0
- package/src/code-tool-types.ts +17 -0
- package/src/code-tool-worker.ts +292 -0
- package/src/code-tool.ts +320 -0
- package/src/docs-search-tool.ts +79 -0
- package/src/http.ts +227 -0
- package/src/index.ts +67 -0
- package/src/instructions.ts +57 -0
- package/src/local-docs-search.ts +738 -0
- package/src/logger.ts +28 -0
- package/src/methods.ts +164 -0
- package/src/options.ts +185 -0
- package/src/server.ts +210 -0
- package/src/stdio.ts +17 -0
- package/src/tsconfig.json +11 -0
- package/src/types.ts +126 -0
- package/src/util.ts +25 -0
- package/stdio.d.mts +3 -0
- package/stdio.d.mts.map +1 -0
- package/stdio.d.ts +3 -0
- package/stdio.d.ts.map +1 -0
- package/stdio.js +18 -0
- package/stdio.js.map +1 -0
- package/stdio.mjs +14 -0
- package/stdio.mjs.map +1 -0
- package/types.d.mts +65 -0
- package/types.d.mts.map +1 -0
- package/types.d.ts +65 -0
- package/types.d.ts.map +1 -0
- package/types.js +58 -0
- package/types.js.map +1 -0
- package/types.mjs +53 -0
- package/types.mjs.map +1 -0
- package/util.d.mts +4 -0
- package/util.d.mts.map +1 -0
- package/util.d.ts +4 -0
- package/util.d.ts.map +1 -0
- package/util.js +30 -0
- package/util.js.map +1 -0
- package/util.mjs +24 -0
- package/util.mjs.map +1 -0
|
@@ -0,0 +1,614 @@
|
|
|
1
|
+
// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
|
|
2
|
+
import MiniSearch from 'minisearch';
|
|
3
|
+
import * as fs from 'node:fs/promises';
|
|
4
|
+
import * as path from 'node:path';
|
|
5
|
+
import { getLogger } from "./logger.mjs";
|
|
6
|
+
const EMBEDDED_METHODS = [
|
|
7
|
+
{
|
|
8
|
+
name: 'generate_grid_points',
|
|
9
|
+
endpoint: '/public/api/v1/heatmap/grid-points',
|
|
10
|
+
httpMethod: 'post',
|
|
11
|
+
summary: 'Generate grid points',
|
|
12
|
+
description: 'Returns the computed grid point coordinates for a given configuration without creating a heatmap.\nUse this to preview a grid layout or to obtain the `points` array that can be passed to\nthe Create Heatmap or Create Schedule endpoints.\n\n`grid_radius` is the spacing between points and is **always in meters** — e.g. `1000` = 1 km, `1609` ≈ 1 mile.\nWhen `polygon` is supplied the grid is clipped to that shape and only points inside it are returned.',
|
|
13
|
+
stainlessPath: '(resource) public.api.v1.heatmap > (method) generate_grid_points',
|
|
14
|
+
qualified: 'client.public.api.v1.heatmap.generateGridPoints',
|
|
15
|
+
params: [
|
|
16
|
+
'grid_radius: number;',
|
|
17
|
+
'grid_size: number;',
|
|
18
|
+
'lat: number;',
|
|
19
|
+
'lng: number;',
|
|
20
|
+
'polygon?: object;',
|
|
21
|
+
],
|
|
22
|
+
response: '{ count?: number; points?: { lat?: number; lng?: number; }[]; }',
|
|
23
|
+
markdown: "## generate_grid_points\n\n`client.public.api.v1.heatmap.generateGridPoints(grid_radius: number, grid_size: number, lat: number, lng: number, polygon?: object): { count?: number; points?: object[]; }`\n\n**post** `/public/api/v1/heatmap/grid-points`\n\nReturns the computed grid point coordinates for a given configuration without creating a heatmap.\nUse this to preview a grid layout or to obtain the `points` array that can be passed to\nthe Create Heatmap or Create Schedule endpoints.\n\n`grid_radius` is the spacing between points and is **always in meters** — e.g. `1000` = 1 km, `1609` ≈ 1 mile.\nWhen `polygon` is supplied the grid is clipped to that shape and only points inside it are returned.\n\n### Parameters\n\n- `grid_radius: number`\n Spacing between grid points, **in meters** (e.g. `1000` = 1 km, `1609` ≈ 1 mile).\n\n- `grid_size: number`\n Number of grid points per side (e.g. 3 = 3×3 grid). Maximum: `13` (produces a 13×13 = 169-point grid).\n\n- `lat: number`\n Latitude of the grid center.\n\n- `lng: number`\n Longitude of the grid center.\n\n- `polygon?: object`\n optional Custom polygon to clip the grid. Points outside the polygon are excluded.\n\n### Returns\n\n- `{ count?: number; points?: { lat?: number; lng?: number; }[]; }`\n\n - `count?: number`\n - `points?: { lat?: number; lng?: number; }[]`\n\n### Example\n\n```typescript\nimport LsTest from 'leadsnap-test-mcp';\n\nconst client = new LsTest();\n\nconst response = await client.public.api.v1.heatmap.generateGridPoints({\n grid_radius: 3495,\n grid_size: 3,\n lat: 44.670381143996,\n lng: -88.122418774951,\n});\n\nconsole.log(response);\n```",
|
|
24
|
+
perLanguage: {
|
|
25
|
+
typescript: {
|
|
26
|
+
method: 'client.public.api.v1.heatmap.generateGridPoints',
|
|
27
|
+
example: "import LsTest from 'leadsnap-test-mcp';\n\nconst client = new LsTest({\n bearerToken: process.env['THRIVE_MCP_BEARER_TOKEN'], // This is the default and can be omitted\n});\n\nconst response = await client.public.api.v1.heatmap.generateGridPoints({\n grid_radius: 3495,\n grid_size: 3,\n lat: 44.670381143996,\n lng: -88.122418774951,\n});\n\nconsole.log(response.count);",
|
|
28
|
+
},
|
|
29
|
+
http: {
|
|
30
|
+
example: 'curl https://app.leadsnap.com/public/api/v1/heatmap/grid-points \\\n -H \'Content-Type: application/json\' \\\n -H "Authorization: Bearer $THRIVE_MCP_BEARER_TOKEN" \\\n -d \'{\n "grid_radius": 3495,\n "grid_size": 3,\n "lat": 44.670381143996,\n "lng": -88.122418774951,\n "polygon": {}\n }\'',
|
|
31
|
+
},
|
|
32
|
+
},
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
name: 'retrieve_heatmap_point',
|
|
36
|
+
endpoint: '/public/api/v1/heatmaps/{heatmap_id}/points/{point_id}',
|
|
37
|
+
httpMethod: 'get',
|
|
38
|
+
summary: 'Get heatmap point',
|
|
39
|
+
description: 'Returns details for a single grid point within a heatmap, including its coordinates, rank, and surrounding place rankings.',
|
|
40
|
+
stainlessPath: '(resource) public.api.v1.heatmap > (method) retrieve_heatmap_point',
|
|
41
|
+
qualified: 'client.public.api.v1.heatmap.retrieveHeatmapPoint',
|
|
42
|
+
params: ['heatmap_id: number;', 'point_id: number;'],
|
|
43
|
+
response: '{ id?: number; index?: number; lat?: number; lng?: number; places?: { id?: number; address?: string; ave_review_rating?: number; google_place_id?: string; name?: string; ranking?: number; review_count?: number; }[]; rank?: number; }',
|
|
44
|
+
markdown: "## retrieve_heatmap_point\n\n`client.public.api.v1.heatmap.retrieveHeatmapPoint(heatmap_id: number, point_id: number): { id?: number; index?: number; lat?: number; lng?: number; places?: object[]; rank?: number; }`\n\n**get** `/public/api/v1/heatmaps/{heatmap_id}/points/{point_id}`\n\nReturns details for a single grid point within a heatmap, including its coordinates, rank, and surrounding place rankings.\n\n### Parameters\n\n- `heatmap_id: number`\n\n- `point_id: number`\n\n### Returns\n\n- `{ id?: number; index?: number; lat?: number; lng?: number; places?: { id?: number; address?: string; ave_review_rating?: number; google_place_id?: string; name?: string; ranking?: number; review_count?: number; }[]; rank?: number; }`\n\n - `id?: number`\n - `index?: number`\n - `lat?: number`\n - `lng?: number`\n - `places?: { id?: number; address?: string; ave_review_rating?: number; google_place_id?: string; name?: string; ranking?: number; review_count?: number; }[]`\n - `rank?: number`\n\n### Example\n\n```typescript\nimport LsTest from 'leadsnap-test-mcp';\n\nconst client = new LsTest();\n\nconst response = await client.public.api.v1.heatmap.retrieveHeatmapPoint(1, { heatmap_id: 1 });\n\nconsole.log(response);\n```",
|
|
45
|
+
perLanguage: {
|
|
46
|
+
typescript: {
|
|
47
|
+
method: 'client.public.api.v1.heatmap.retrieveHeatmapPoint',
|
|
48
|
+
example: "import LsTest from 'leadsnap-test-mcp';\n\nconst client = new LsTest({\n bearerToken: process.env['THRIVE_MCP_BEARER_TOKEN'], // This is the default and can be omitted\n});\n\nconst response = await client.public.api.v1.heatmap.retrieveHeatmapPoint(1, { heatmap_id: 1 });\n\nconsole.log(response.id);",
|
|
49
|
+
},
|
|
50
|
+
http: {
|
|
51
|
+
example: 'curl https://app.leadsnap.com/public/api/v1/heatmaps/$HEATMAP_ID/points/$POINT_ID \\\n -H "Authorization: Bearer $THRIVE_MCP_BEARER_TOKEN"',
|
|
52
|
+
},
|
|
53
|
+
},
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
name: 'list_heatmaps',
|
|
57
|
+
endpoint: '/public/api/v1/heatmaps',
|
|
58
|
+
httpMethod: 'get',
|
|
59
|
+
summary: 'List heatmaps',
|
|
60
|
+
description: 'Returns a paginated list of heatmaps for the authenticated account. Supports filtering, sorting, searching, and pagination.\n\n**Pagination** — all list responses include pagination fields at the root level alongside `data`:\n- `total` total matching records; `last_page` total pages; `per_page` results per page (default 25)\n- `next_page_url` URL of the next page (`null` on the last page)\n- `links` array of page link objects (`url`, `label`, `active`)\n\n**Date filters** — `filter[created_at]` accepts an object with `start_date` and/or `end_date` (YYYY-MM-DD):\n```\nfilter[created_at][start_date]=2026-01-01\nfilter[created_at][end_date]=2026-04-30\n```\nAlternatively, pass a named range alias via `filter[created_at][date]`:\n`today`, `yesterday`, `this_week`, `last_week`, `last_7_days`, `last_30_days`, `last_90_days`,\n`this_month`, `last_month`, `this_quarter`, `last_quarter`, `this_year`, `year_to_date`, `last_year`, `all_time`',
|
|
61
|
+
stainlessPath: '(resource) public.api.v1.heatmap > (method) list_heatmaps',
|
|
62
|
+
qualified: 'client.public.api.v1.heatmap.listHeatmaps',
|
|
63
|
+
params: [
|
|
64
|
+
'filter[business_name]?: string;',
|
|
65
|
+
'filter[company_id]?: number;',
|
|
66
|
+
'filter[created_at][date]?: string;',
|
|
67
|
+
'filter[created_at][end_date]?: string;',
|
|
68
|
+
'filter[created_at][start_date]?: string;',
|
|
69
|
+
'filter[google_place_id]?: string;',
|
|
70
|
+
'filter[keyword]?: string;',
|
|
71
|
+
'filter[location_id]?: number;',
|
|
72
|
+
'filter[search_type]?: string;',
|
|
73
|
+
'filter[status]?: string;',
|
|
74
|
+
'filter[tag]?: string;',
|
|
75
|
+
'page?: number;',
|
|
76
|
+
'per_page?: number;',
|
|
77
|
+
'search?: string;',
|
|
78
|
+
'sort?: string;',
|
|
79
|
+
],
|
|
80
|
+
response: '{ current_page?: number; data?: { id?: number; area?: string; ave_review_rating?: string; average?: string; average_position?: string; business_name?: string; business_place_id?: string; created_at?: string; grid_center_lat?: number; grid_center_lng?: number; grid_distance_measure?: string; grid_point_distance?: string; grid_point_distance_row?: number; grid_size?: number; keyword?: string; lead_source_id?: string; location?: string; location_id?: string; market_share?: string; market_share_position?: string; place?: object; place_id?: number; previous_ranking?: string; ranking_change?: string; ranking_change_percentage?: string; review_count?: string; search_type?: string; status?: string; status_code?: number; top_3_percentage?: string; top_3_points?: string; top_3_position?: string; top_n?: string; total?: string; total_points?: string; updated_at?: string; zoom_level?: string; }[]; first_page_url?: string; from?: number; last_page?: number; last_page_url?: string; links?: object[]; next_page_url?: string; path?: string; per_page?: number; prev_page_url?: string; to?: number; total?: number; }',
|
|
81
|
+
markdown: "## list_heatmaps\n\n`client.public.api.v1.heatmap.listHeatmaps(filter[business_name]?: string, filter[company_id]?: number, filter[created_at][date]?: string, filter[created_at][end_date]?: string, filter[created_at][start_date]?: string, filter[google_place_id]?: string, filter[keyword]?: string, filter[location_id]?: number, filter[search_type]?: string, filter[status]?: string, filter[tag]?: string, page?: number, per_page?: number, search?: string, sort?: string): { current_page?: number; data?: object[]; first_page_url?: string; from?: number; last_page?: number; last_page_url?: string; links?: object[]; next_page_url?: string; path?: string; per_page?: number; prev_page_url?: string; to?: number; total?: number; }`\n\n**get** `/public/api/v1/heatmaps`\n\nReturns a paginated list of heatmaps for the authenticated account. Supports filtering, sorting, searching, and pagination.\n\n**Pagination** — all list responses include pagination fields at the root level alongside `data`:\n- `total` total matching records; `last_page` total pages; `per_page` results per page (default 25)\n- `next_page_url` URL of the next page (`null` on the last page)\n- `links` array of page link objects (`url`, `label`, `active`)\n\n**Date filters** — `filter[created_at]` accepts an object with `start_date` and/or `end_date` (YYYY-MM-DD):\n```\nfilter[created_at][start_date]=2026-01-01\nfilter[created_at][end_date]=2026-04-30\n```\nAlternatively, pass a named range alias via `filter[created_at][date]`:\n`today`, `yesterday`, `this_week`, `last_week`, `last_7_days`, `last_30_days`, `last_90_days`,\n`this_month`, `last_month`, `this_quarter`, `last_quarter`, `this_year`, `year_to_date`, `last_year`, `all_time`\n\n### Parameters\n\n- `filter[business_name]?: string`\n Filter by business name (partial match).\n\n- `filter[company_id]?: number`\n Filter by lead source / company ID.\n\n- `filter[created_at][date]?: string`\n Filter by a named date alias instead of a range. Accepted: `today`, `yesterday`, `this_week`, `last_week`, `last_7_days`, `last_30_days`, `last_90_days`, `this_month`, `last_month`, `this_quarter`, `last_quarter`, `this_year`, `year_to_date`, `last_year`, `all_time`.\n\n- `filter[created_at][end_date]?: string`\n Filter by creation date — range end (YYYY-MM-DD).\n\n- `filter[created_at][start_date]?: string`\n Filter by creation date — range start (YYYY-MM-DD).\n\n- `filter[google_place_id]?: string`\n Filter by Google Place ID (exact).\n\n- `filter[keyword]?: string`\n Filter by keyword text (partial match).\n\n- `filter[location_id]?: number`\n Filter by location ID.\n\n- `filter[search_type]?: string`\n Filter by search type. Accepted: `google_maps`, `local_pack`.\n\n- `filter[status]?: string`\n Filter by heatmap status. Accepted slugs: `queue`, `in_progress`, `completed`, `incomplete`, `failed`. Numeric values (0–4) are also accepted.\n\n- `filter[tag]?: string`\n Filter by tag name (exact match).\n\n- `page?: number`\n Page number.\n\n- `per_page?: number`\n Number of results per page (default 25).\n\n- `search?: string`\n Full-text search across keyword and business name.\n\n- `sort?: string`\n Sort field. Prefix with `-` for descending. Accepted: `created_at`, `average`, `top_3_points`, `top_3_position`, `top_3_percentage`, `review_count`, `review_rating`, `average_position`, `zoom_level`, `grid_size`, `market_share`, `keyword`, `business_name`, `reviews`.\n\n### Returns\n\n- `{ current_page?: number; data?: { id?: number; area?: string; ave_review_rating?: string; average?: string; average_position?: string; business_name?: string; business_place_id?: string; created_at?: string; grid_center_lat?: number; grid_center_lng?: number; grid_distance_measure?: string; grid_point_distance?: string; grid_point_distance_row?: number; grid_size?: number; keyword?: string; lead_source_id?: string; location?: string; location_id?: string; market_share?: string; market_share_position?: string; place?: { id?: number; address?: string; ave_review_rating?: number; feature_id?: string; google_place_id?: string; google_place_serial?: string; latitude?: string; longitude?: string; main_category?: string; map_url?: string; name?: string; phone?: string; place_url?: string; ranking?: string; related_categories?: string[]; review_count?: number; thumbnail_url?: string; website_url?: string; }; place_id?: number; previous_ranking?: string; ranking_change?: string; ranking_change_percentage?: string; review_count?: string; search_type?: string; status?: string; status_code?: number; top_3_percentage?: string; top_3_points?: string; top_3_position?: string; top_n?: string; total?: string; total_points?: string; updated_at?: string; zoom_level?: string; }[]; first_page_url?: string; from?: number; last_page?: number; last_page_url?: string; links?: object[]; next_page_url?: string; path?: string; per_page?: number; prev_page_url?: string; to?: number; total?: number; }`\n\n - `current_page?: number`\n - `data?: { id?: number; area?: string; ave_review_rating?: string; average?: string; average_position?: string; business_name?: string; business_place_id?: string; created_at?: string; grid_center_lat?: number; grid_center_lng?: number; grid_distance_measure?: string; grid_point_distance?: string; grid_point_distance_row?: number; grid_size?: number; keyword?: string; lead_source_id?: string; location?: string; location_id?: string; market_share?: string; market_share_position?: string; place?: { id?: number; address?: string; ave_review_rating?: number; feature_id?: string; google_place_id?: string; google_place_serial?: string; latitude?: string; longitude?: string; main_category?: string; map_url?: string; name?: string; phone?: string; place_url?: string; ranking?: string; related_categories?: string[]; review_count?: number; thumbnail_url?: string; website_url?: string; }; place_id?: number; previous_ranking?: string; ranking_change?: string; ranking_change_percentage?: string; review_count?: string; search_type?: string; status?: string; status_code?: number; top_3_percentage?: string; top_3_points?: string; top_3_position?: string; top_n?: string; total?: string; total_points?: string; updated_at?: string; zoom_level?: string; }[]`\n - `first_page_url?: string`\n - `from?: number`\n - `last_page?: number`\n - `last_page_url?: string`\n - `links?: object[]`\n - `next_page_url?: string`\n - `path?: string`\n - `per_page?: number`\n - `prev_page_url?: string`\n - `to?: number`\n - `total?: number`\n\n### Example\n\n```typescript\nimport LsTest from 'leadsnap-test-mcp';\n\nconst client = new LsTest();\n\nconst response = await client.public.api.v1.heatmap.listHeatmaps();\n\nconsole.log(response);\n```",
|
|
82
|
+
perLanguage: {
|
|
83
|
+
typescript: {
|
|
84
|
+
method: 'client.public.api.v1.heatmap.listHeatmaps',
|
|
85
|
+
example: "import LsTest from 'leadsnap-test-mcp';\n\nconst client = new LsTest({\n bearerToken: process.env['THRIVE_MCP_BEARER_TOKEN'], // This is the default and can be omitted\n});\n\nconst response = await client.public.api.v1.heatmap.listHeatmaps();\n\nconsole.log(response.current_page);",
|
|
86
|
+
},
|
|
87
|
+
http: {
|
|
88
|
+
example: 'curl https://app.leadsnap.com/public/api/v1/heatmaps \\\n -H "Authorization: Bearer $THRIVE_MCP_BEARER_TOKEN"',
|
|
89
|
+
},
|
|
90
|
+
},
|
|
91
|
+
},
|
|
92
|
+
{
|
|
93
|
+
name: 'create_heatmap',
|
|
94
|
+
endpoint: '/public/api/v1/heatmaps',
|
|
95
|
+
httpMethod: 'post',
|
|
96
|
+
summary: 'Create heatmap',
|
|
97
|
+
description: 'Creates one or more heatmaps. Each combination of keyword × search_type generates a separate heatmap.',
|
|
98
|
+
stainlessPath: '(resource) public.api.v1.heatmap > (method) create_heatmap',
|
|
99
|
+
qualified: 'client.public.api.v1.heatmap.createHeatmap',
|
|
100
|
+
params: [
|
|
101
|
+
'distanceType: string;',
|
|
102
|
+
'grid_radius: number;',
|
|
103
|
+
'grid_size: number;',
|
|
104
|
+
'keyword: string[];',
|
|
105
|
+
'lat: number;',
|
|
106
|
+
'lng: number;',
|
|
107
|
+
'place_id: string;',
|
|
108
|
+
'search_type: string[];',
|
|
109
|
+
'points?: { lat: number; lng: number; }[];',
|
|
110
|
+
],
|
|
111
|
+
response: '{ id?: number; area?: string; ave_review_rating?: string; average?: string; average_position?: string; business_name?: string; business_place_id?: string; created_at?: string; grid_center_lat?: number; grid_center_lng?: number; grid_distance_measure?: string; grid_point_distance?: string; grid_point_distance_row?: number; grid_size?: number; keyword?: string; keyword_difficulty?: string; keyword_search_intents?: object[]; lead_source_id?: string; location?: string; location_id?: string; market_share?: string; market_share_position?: string; place?: string; place_id?: string; points?: object[]; previous_ranking?: string; ranking_change?: string; ranking_change_percentage?: string; review_count?: string; search_type?: string; search_volume?: string; status?: string; tags?: object[]; top_3_percentage?: string; top_3_points?: number; top_3_position?: string; top_n?: string; total?: number; total_points?: number; updated_at?: string; zoom_level?: string; }',
|
|
112
|
+
markdown: "## create_heatmap\n\n`client.public.api.v1.heatmap.createHeatmap(distanceType: string, grid_radius: number, grid_size: number, keyword: string[], lat: number, lng: number, place_id: string, search_type: string[], points?: { lat: number; lng: number; }[]): { id?: number; area?: string; ave_review_rating?: string; average?: string; average_position?: string; business_name?: string; business_place_id?: string; created_at?: string; grid_center_lat?: number; grid_center_lng?: number; grid_distance_measure?: string; grid_point_distance?: string; grid_point_distance_row?: number; grid_size?: number; keyword?: string; keyword_difficulty?: string; keyword_search_intents?: object[]; lead_source_id?: string; location?: string; location_id?: string; market_share?: string; market_share_position?: string; place?: string; place_id?: string; points?: object[]; previous_ranking?: string; ranking_change?: string; ranking_change_percentage?: string; review_count?: string; search_type?: string; search_volume?: string; status?: string; tags?: object[]; top_3_percentage?: string; top_3_points?: number; top_3_position?: string; top_n?: string; total?: number; total_points?: number; updated_at?: string; zoom_level?: string; }`\n\n**post** `/public/api/v1/heatmaps`\n\nCreates one or more heatmaps. Each combination of keyword × search_type generates a separate heatmap.\n\n### Parameters\n\n- `distanceType: string`\n Unit for the radius. Accepted: `km`, `mi`, `m`.\n\n- `grid_radius: number`\n Radius between grid points in the chosen unit. Used to auto-generate points when `points` is not provided.\n\n- `grid_size: number`\n Number of grid points per side (e.g. 3 = 3×3). Maximum: `13` (13×13 = 169 points). Used to auto-generate points when `points` is not provided.\n\n- `keyword: string[]`\n Keywords to track.\n\n- `lat: number`\n Latitude of the grid center.\n\n- `lng: number`\n Longitude of the grid center.\n\n- `place_id: string`\n Google Place ID of the business. you can get the place_id by calling heatmaps/locations endpoint in case you don't have it.\n\n- `search_type: string[]`\n Search type(s) to run per keyword. Accepted: `google_maps`, `local_pack`.\n\n- `points?: { lat: number; lng: number; }[]`\n optional Pre-computed grid point coordinates (max 169). If provided (must not be empty), `grid_radius` and `grid_size` are ignored. If omitted,\npoints are auto-generated from `grid_size` and `grid_radius`. Use the [Generate grid points](#tag/Heatmap-Points/POST/public/api/v1/heatmap/grid-points) endpoint to compute coordinates from a grid config and pass them here.\n\n### Returns\n\n- `{ id?: number; area?: string; ave_review_rating?: string; average?: string; average_position?: string; business_name?: string; business_place_id?: string; created_at?: string; grid_center_lat?: number; grid_center_lng?: number; grid_distance_measure?: string; grid_point_distance?: string; grid_point_distance_row?: number; grid_size?: number; keyword?: string; keyword_difficulty?: string; keyword_search_intents?: object[]; lead_source_id?: string; location?: string; location_id?: string; market_share?: string; market_share_position?: string; place?: string; place_id?: string; points?: object[]; previous_ranking?: string; ranking_change?: string; ranking_change_percentage?: string; review_count?: string; search_type?: string; search_volume?: string; status?: string; tags?: object[]; top_3_percentage?: string; top_3_points?: number; top_3_position?: string; top_n?: string; total?: number; total_points?: number; updated_at?: string; zoom_level?: string; }`\n\n - `id?: number`\n - `area?: string`\n - `ave_review_rating?: string`\n - `average?: string`\n - `average_position?: string`\n - `business_name?: string`\n - `business_place_id?: string`\n - `created_at?: string`\n - `grid_center_lat?: number`\n - `grid_center_lng?: number`\n - `grid_distance_measure?: string`\n - `grid_point_distance?: string`\n - `grid_point_distance_row?: number`\n - `grid_size?: number`\n - `keyword?: string`\n - `keyword_difficulty?: string`\n - `keyword_search_intents?: object[]`\n - `lead_source_id?: string`\n - `location?: string`\n - `location_id?: string`\n - `market_share?: string`\n - `market_share_position?: string`\n - `place?: string`\n - `place_id?: string`\n - `points?: object[]`\n - `previous_ranking?: string`\n - `ranking_change?: string`\n - `ranking_change_percentage?: string`\n - `review_count?: string`\n - `search_type?: string`\n - `search_volume?: string`\n - `status?: string`\n - `tags?: object[]`\n - `top_3_percentage?: string`\n - `top_3_points?: number`\n - `top_3_position?: string`\n - `top_n?: string`\n - `total?: number`\n - `total_points?: number`\n - `updated_at?: string`\n - `zoom_level?: string`\n\n### Example\n\n```typescript\nimport LsTest from 'leadsnap-test-mcp';\n\nconst client = new LsTest();\n\nconst response = await client.public.api.v1.heatmap.createHeatmap({\n distanceType: 'm',\n grid_radius: 3495,\n grid_size: 3,\n keyword: ['roofing'],\n lat: 44.670381143996,\n lng: -88.122418774951,\n place_id: 'ChIJFzfDtmDzAogRn0zn9LJaP_A',\n search_type: ['google_maps'],\n});\n\nconsole.log(response);\n```",
|
|
113
|
+
perLanguage: {
|
|
114
|
+
typescript: {
|
|
115
|
+
method: 'client.public.api.v1.heatmap.createHeatmap',
|
|
116
|
+
example: "import LsTest from 'leadsnap-test-mcp';\n\nconst client = new LsTest({\n bearerToken: process.env['THRIVE_MCP_BEARER_TOKEN'], // This is the default and can be omitted\n});\n\nconst response = await client.public.api.v1.heatmap.createHeatmap({\n distanceType: 'm',\n grid_radius: 3495,\n grid_size: 3,\n keyword: ['roofing'],\n lat: 44.670381143996,\n lng: -88.122418774951,\n place_id: 'ChIJFzfDtmDzAogRn0zn9LJaP_A',\n search_type: ['google_maps'],\n});\n\nconsole.log(response.id);",
|
|
117
|
+
},
|
|
118
|
+
http: {
|
|
119
|
+
example: 'curl https://app.leadsnap.com/public/api/v1/heatmaps \\\n -H \'Content-Type: application/json\' \\\n -H "Authorization: Bearer $THRIVE_MCP_BEARER_TOKEN" \\\n -d \'{\n "distanceType": "m",\n "grid_radius": 3495,\n "grid_size": 3,\n "keyword": [\n "roofing"\n ],\n "lat": 44.670381143996,\n "lng": -88.122418774951,\n "place_id": "ChIJFzfDtmDzAogRn0zn9LJaP_A",\n "search_type": [\n "google_maps"\n ],\n "points": [\n {\n "lat": 44.626765686401,\n "lng": -88.078293153604\n },\n {\n "lat": 44.626765686401,\n "lng": -88.100354964951\n }\n ]\n }\'',
|
|
120
|
+
},
|
|
121
|
+
},
|
|
122
|
+
},
|
|
123
|
+
{
|
|
124
|
+
name: 'list_locations',
|
|
125
|
+
endpoint: '/public/api/v1/heatmaps/locations',
|
|
126
|
+
httpMethod: 'get',
|
|
127
|
+
summary: 'List locations',
|
|
128
|
+
description: 'Returns a paginated list of Google Business Profile locations for the authenticated account. Supports filtering, sorting, searching, and pagination.\n\n**Pagination** — all list responses include pagination fields at the root level alongside `data`:\n- `total` total matching records; `last_page` total pages; `per_page` results per page (default 25)\n- `next_page_url` URL of the next page (`null` on the last page)\n- `links` array of page link objects (`url`, `label`, `active`)',
|
|
129
|
+
stainlessPath: '(resource) public.api.v1.heatmap > (method) list_locations',
|
|
130
|
+
qualified: 'client.public.api.v1.heatmap.listLocations',
|
|
131
|
+
params: [
|
|
132
|
+
'filter[address]?: string;',
|
|
133
|
+
'filter[city]?: string;',
|
|
134
|
+
'filter[id]?: number;',
|
|
135
|
+
'filter[location_name]?: string;',
|
|
136
|
+
'filter[place_id]?: string;',
|
|
137
|
+
'filter[primary_category]?: string;',
|
|
138
|
+
'filter[state]?: string;',
|
|
139
|
+
'filter[zip_code]?: string;',
|
|
140
|
+
'page?: number;',
|
|
141
|
+
'per_page?: number;',
|
|
142
|
+
'sort?: string;',
|
|
143
|
+
],
|
|
144
|
+
response: '{ current_page?: number; data?: object[]; first_page_url?: string; from?: number; last_page?: number; last_page_url?: string; links?: object[]; next_page_url?: string; path?: string; per_page?: number; prev_page_url?: string; to?: number; total?: number; }',
|
|
145
|
+
markdown: "## list_locations\n\n`client.public.api.v1.heatmap.listLocations(filter[address]?: string, filter[city]?: string, filter[id]?: number, filter[location_name]?: string, filter[place_id]?: string, filter[primary_category]?: string, filter[state]?: string, filter[zip_code]?: string, page?: number, per_page?: number, sort?: string): { current_page?: number; data?: object[]; first_page_url?: string; from?: number; last_page?: number; last_page_url?: string; links?: object[]; next_page_url?: string; path?: string; per_page?: number; prev_page_url?: string; to?: number; total?: number; }`\n\n**get** `/public/api/v1/heatmaps/locations`\n\nReturns a paginated list of Google Business Profile locations for the authenticated account. Supports filtering, sorting, searching, and pagination.\n\n**Pagination** — all list responses include pagination fields at the root level alongside `data`:\n- `total` total matching records; `last_page` total pages; `per_page` results per page (default 25)\n- `next_page_url` URL of the next page (`null` on the last page)\n- `links` array of page link objects (`url`, `label`, `active`)\n\n### Parameters\n\n- `filter[address]?: string`\n Filter by address (partial match).\n\n- `filter[city]?: string`\n Filter by city.\n\n- `filter[id]?: number`\n Filter by location ID.\n\n- `filter[location_name]?: string`\n Filter by location name (partial match).\n\n- `filter[place_id]?: string`\n Filter by Google Place ID (exact).\n\n- `filter[primary_category]?: string`\n Filter by primary business category.\n\n- `filter[state]?: string`\n Filter by state.\n\n- `filter[zip_code]?: string`\n Filter by zip code.\n\n- `page?: number`\n Page number.\n\n- `per_page?: number`\n Number of results per page (default 25).\n\n- `sort?: string`\n Sort field. Prefix with `-` for descending. Accepted: `location_name`, `address`, `city`, `state`, `zip_code`, `primary_category`, `website_url`, `review_count`, `ave_review_rating`, `created_at`, `last_review_date`, `is_connected`, `location_state`, `media_count`, `unreplied_review_count`, `completion_percentage`.\n\n### Returns\n\n- `{ current_page?: number; data?: { id?: number; address?: string; ave_review_rating?: number; citation?: string; city?: string; completion_percentage?: number; country?: string; created_at?: string; currency?: string; deleted_at?: string; description?: string; email?: string; image?: string; is_authorized?: string; is_citation_subscribed?: boolean; is_connected?: number; is_gmb_activate?: number; last_review_date?: string; latitude?: number; location_id?: string; location_image?: string; location_name?: string; location_name_initials?: string; location_state?: string; lock_changes?: number; longitude?: number; map_url?: string; media_count?: number; name?: string; place_id?: string; primary_category?: string; primary_phone?: string; review_count?: number; review_link?: string; review_url?: string; state?: string; status?: string; subscription_id?: number; subscription_item_id?: number; unreplied_review_count?: number; updated_at?: string; website_url?: string; zip?: string; zip_code?: string; }[]; first_page_url?: string; from?: number; last_page?: number; last_page_url?: string; links?: object[]; next_page_url?: string; path?: string; per_page?: number; prev_page_url?: string; to?: number; total?: number; }`\n\n - `current_page?: number`\n - `data?: { id?: number; address?: string; ave_review_rating?: number; citation?: string; city?: string; completion_percentage?: number; country?: string; created_at?: string; currency?: string; deleted_at?: string; description?: string; email?: string; image?: string; is_authorized?: string; is_citation_subscribed?: boolean; is_connected?: number; is_gmb_activate?: number; last_review_date?: string; latitude?: number; location_id?: string; location_image?: string; location_name?: string; location_name_initials?: string; location_state?: string; lock_changes?: number; longitude?: number; map_url?: string; media_count?: number; name?: string; place_id?: string; primary_category?: string; primary_phone?: string; review_count?: number; review_link?: string; review_url?: string; state?: string; status?: string; subscription_id?: number; subscription_item_id?: number; unreplied_review_count?: number; updated_at?: string; website_url?: string; zip?: string; zip_code?: string; }[]`\n - `first_page_url?: string`\n - `from?: number`\n - `last_page?: number`\n - `last_page_url?: string`\n - `links?: object[]`\n - `next_page_url?: string`\n - `path?: string`\n - `per_page?: number`\n - `prev_page_url?: string`\n - `to?: number`\n - `total?: number`\n\n### Example\n\n```typescript\nimport LsTest from 'leadsnap-test-mcp';\n\nconst client = new LsTest();\n\nconst response = await client.public.api.v1.heatmap.listLocations();\n\nconsole.log(response);\n```",
|
|
146
|
+
perLanguage: {
|
|
147
|
+
typescript: {
|
|
148
|
+
method: 'client.public.api.v1.heatmap.listLocations',
|
|
149
|
+
example: "import LsTest from 'leadsnap-test-mcp';\n\nconst client = new LsTest({\n bearerToken: process.env['THRIVE_MCP_BEARER_TOKEN'], // This is the default and can be omitted\n});\n\nconst response = await client.public.api.v1.heatmap.listLocations();\n\nconsole.log(response.current_page);",
|
|
150
|
+
},
|
|
151
|
+
http: {
|
|
152
|
+
example: 'curl https://app.leadsnap.com/public/api/v1/heatmaps/locations \\\n -H "Authorization: Bearer $THRIVE_MCP_BEARER_TOKEN"',
|
|
153
|
+
},
|
|
154
|
+
},
|
|
155
|
+
},
|
|
156
|
+
{
|
|
157
|
+
name: 'retrieve_heatmap',
|
|
158
|
+
endpoint: '/public/api/v1/heatmaps/{heatmap}',
|
|
159
|
+
httpMethod: 'get',
|
|
160
|
+
summary: 'Get heatmap',
|
|
161
|
+
description: 'Returns full details of a single heatmap including grid points, place info, and ranking statistics.',
|
|
162
|
+
stainlessPath: '(resource) public.api.v1.heatmap > (method) retrieve_heatmap',
|
|
163
|
+
qualified: 'client.public.api.v1.heatmap.retrieveHeatmap',
|
|
164
|
+
params: ['heatmap: number;'],
|
|
165
|
+
response: '{ id?: number; area?: string; ave_review_rating?: number; average?: string; average_position?: number; business_name?: string; business_place_id?: string; created_at?: string; grid_center_lat?: number; grid_center_lng?: number; grid_distance_measure?: string; grid_point_distance?: string; grid_point_distance_row?: number; grid_size?: number; keyword?: string; keyword_seo_data?: object; lead_source_id?: string; location?: string; location_id?: string; market_share?: string; market_share_position?: number; place?: object; place_id?: number; points?: object[]; previous_ranking?: string; ranking_change?: string; ranking_change_percentage?: string; review_count?: number; search_type?: string; status?: string; status_code?: number; tags?: object[]; top_3_percentage?: number; top_3_points?: number; top_3_position?: number; top_n?: number; total?: number; total_points?: number; updated_at?: string; zoom_level?: string; }',
|
|
166
|
+
markdown: "## retrieve_heatmap\n\n`client.public.api.v1.heatmap.retrieveHeatmap(heatmap: number): { id?: number; area?: string; ave_review_rating?: number; average?: string; average_position?: number; business_name?: string; business_place_id?: string; created_at?: string; grid_center_lat?: number; grid_center_lng?: number; grid_distance_measure?: string; grid_point_distance?: string; grid_point_distance_row?: number; grid_size?: number; keyword?: string; keyword_seo_data?: object; lead_source_id?: string; location?: string; location_id?: string; market_share?: string; market_share_position?: number; place?: object; place_id?: number; points?: object[]; previous_ranking?: string; ranking_change?: string; ranking_change_percentage?: string; review_count?: number; search_type?: string; status?: string; status_code?: number; tags?: object[]; top_3_percentage?: number; top_3_points?: number; top_3_position?: number; top_n?: number; total?: number; total_points?: number; updated_at?: string; zoom_level?: string; }`\n\n**get** `/public/api/v1/heatmaps/{heatmap}`\n\nReturns full details of a single heatmap including grid points, place info, and ranking statistics.\n\n### Parameters\n\n- `heatmap: number`\n\n### Returns\n\n- `{ id?: number; area?: string; ave_review_rating?: number; average?: string; average_position?: number; business_name?: string; business_place_id?: string; created_at?: string; grid_center_lat?: number; grid_center_lng?: number; grid_distance_measure?: string; grid_point_distance?: string; grid_point_distance_row?: number; grid_size?: number; keyword?: string; keyword_seo_data?: { id?: number; account_id?: number; created_at?: string; heatmap_keyword_list_id?: number; keyword?: string; keyword_difficulty?: { id?: number; created_at?: string; difficulty?: number; keyword?: string; language_code?: string; location_code?: string; updated_at?: string; }; keyword_search_intents?: { id?: number; created_at?: string; keyword?: string; label?: string; language_code?: string; probability?: number; updated_at?: string; }[]; search_volume?: { id?: number; competition?: string; competition_index?: number; cpc?: string; created_at?: string; high_top_of_page_bid?: string; keyword?: string; language_code?: string; location_code?: string; low_top_of_page_bid?: string; search_volume?: number; updated_at?: string; }; updated_at?: string; }; lead_source_id?: string; location?: string; location_id?: string; market_share?: string; market_share_position?: number; place?: { id?: number; address?: string; ave_review_rating?: number; feature_id?: string; google_place_id?: string; google_place_serial?: string; latitude?: string; longitude?: string; main_category?: string; map_url?: string; name?: string; phone?: string; place_url?: string; ranking?: string; related_categories?: string[]; review_count?: number; thumbnail_url?: string; website_url?: string; }; place_id?: number; points?: { id?: number; index?: number; lat?: string; lng?: string; rank?: number; }[]; previous_ranking?: string; ranking_change?: string; ranking_change_percentage?: string; review_count?: number; search_type?: string; status?: string; status_code?: number; tags?: object[]; top_3_percentage?: number; top_3_points?: number; top_3_position?: number; top_n?: number; total?: number; total_points?: number; updated_at?: string; zoom_level?: string; }`\n\n - `id?: number`\n - `area?: string`\n - `ave_review_rating?: number`\n - `average?: string`\n - `average_position?: number`\n - `business_name?: string`\n - `business_place_id?: string`\n - `created_at?: string`\n - `grid_center_lat?: number`\n - `grid_center_lng?: number`\n - `grid_distance_measure?: string`\n - `grid_point_distance?: string`\n - `grid_point_distance_row?: number`\n - `grid_size?: number`\n - `keyword?: string`\n - `keyword_seo_data?: { id?: number; account_id?: number; created_at?: string; heatmap_keyword_list_id?: number; keyword?: string; keyword_difficulty?: { id?: number; created_at?: string; difficulty?: number; keyword?: string; language_code?: string; location_code?: string; updated_at?: string; }; keyword_search_intents?: { id?: number; created_at?: string; keyword?: string; label?: string; language_code?: string; probability?: number; updated_at?: string; }[]; search_volume?: { id?: number; competition?: string; competition_index?: number; cpc?: string; created_at?: string; high_top_of_page_bid?: string; keyword?: string; language_code?: string; location_code?: string; low_top_of_page_bid?: string; search_volume?: number; updated_at?: string; }; updated_at?: string; }`\n - `lead_source_id?: string`\n - `location?: string`\n - `location_id?: string`\n - `market_share?: string`\n - `market_share_position?: number`\n - `place?: { id?: number; address?: string; ave_review_rating?: number; feature_id?: string; google_place_id?: string; google_place_serial?: string; latitude?: string; longitude?: string; main_category?: string; map_url?: string; name?: string; phone?: string; place_url?: string; ranking?: string; related_categories?: string[]; review_count?: number; thumbnail_url?: string; website_url?: string; }`\n - `place_id?: number`\n - `points?: { id?: number; index?: number; lat?: string; lng?: string; rank?: number; }[]`\n - `previous_ranking?: string`\n - `ranking_change?: string`\n - `ranking_change_percentage?: string`\n - `review_count?: number`\n - `search_type?: string`\n - `status?: string`\n - `status_code?: number`\n - `tags?: object[]`\n - `top_3_percentage?: number`\n - `top_3_points?: number`\n - `top_3_position?: number`\n - `top_n?: number`\n - `total?: number`\n - `total_points?: number`\n - `updated_at?: string`\n - `zoom_level?: string`\n\n### Example\n\n```typescript\nimport LsTest from 'leadsnap-test-mcp';\n\nconst client = new LsTest();\n\nconst response = await client.public.api.v1.heatmap.retrieveHeatmap(1482);\n\nconsole.log(response);\n```",
|
|
167
|
+
perLanguage: {
|
|
168
|
+
typescript: {
|
|
169
|
+
method: 'client.public.api.v1.heatmap.retrieveHeatmap',
|
|
170
|
+
example: "import LsTest from 'leadsnap-test-mcp';\n\nconst client = new LsTest({\n bearerToken: process.env['THRIVE_MCP_BEARER_TOKEN'], // This is the default and can be omitted\n});\n\nconst response = await client.public.api.v1.heatmap.retrieveHeatmap(1482);\n\nconsole.log(response.id);",
|
|
171
|
+
},
|
|
172
|
+
http: {
|
|
173
|
+
example: 'curl https://app.leadsnap.com/public/api/v1/heatmaps/$HEATMAP \\\n -H "Authorization: Bearer $THRIVE_MCP_BEARER_TOKEN"',
|
|
174
|
+
},
|
|
175
|
+
},
|
|
176
|
+
},
|
|
177
|
+
{
|
|
178
|
+
name: 'retrieve_heatmap_competitors',
|
|
179
|
+
endpoint: '/public/api/v1/heatmaps/{heatmap}/competitors',
|
|
180
|
+
httpMethod: 'get',
|
|
181
|
+
summary: 'Get heatmap competitors',
|
|
182
|
+
description: 'Returns aggregated ranking statistics for all competitor businesses found across the grid points of the specified heatmap.',
|
|
183
|
+
stainlessPath: '(resource) public.api.v1.heatmap > (method) retrieve_heatmap_competitors',
|
|
184
|
+
qualified: 'client.public.api.v1.heatmap.retrieveHeatmapCompetitors',
|
|
185
|
+
params: ['heatmap: number;'],
|
|
186
|
+
response: '{ id?: number; average?: number; average_position?: number; market_share?: string; market_share_position?: number; north_east?: number; north_west?: number; photos_count?: number; place?: { id?: number; address?: string; ave_review_rating?: number; feature_id?: string; google_place_id?: string; google_place_serial?: string; latitude?: string; longitude?: string; main_category?: string; map_url?: string; name?: string; phone?: string; place_url?: string; ranking?: string; related_categories?: string[]; review_count?: number; thumbnail_url?: string; website_url?: string; }; south_east?: number; south_west?: number; top_20_points?: number; top_3_percentage?: string; top_3_points?: number; top_3_position?: number; total_points?: number; }[]',
|
|
187
|
+
markdown: "## retrieve_heatmap_competitors\n\n`client.public.api.v1.heatmap.retrieveHeatmapCompetitors(heatmap: number): { id?: number; average?: number; average_position?: number; market_share?: string; market_share_position?: number; north_east?: number; north_west?: number; photos_count?: number; place?: object; south_east?: number; south_west?: number; top_20_points?: number; top_3_percentage?: string; top_3_points?: number; top_3_position?: number; total_points?: number; }[]`\n\n**get** `/public/api/v1/heatmaps/{heatmap}/competitors`\n\nReturns aggregated ranking statistics for all competitor businesses found across the grid points of the specified heatmap.\n\n### Parameters\n\n- `heatmap: number`\n\n### Returns\n\n- `{ id?: number; average?: number; average_position?: number; market_share?: string; market_share_position?: number; north_east?: number; north_west?: number; photos_count?: number; place?: { id?: number; address?: string; ave_review_rating?: number; feature_id?: string; google_place_id?: string; google_place_serial?: string; latitude?: string; longitude?: string; main_category?: string; map_url?: string; name?: string; phone?: string; place_url?: string; ranking?: string; related_categories?: string[]; review_count?: number; thumbnail_url?: string; website_url?: string; }; south_east?: number; south_west?: number; top_20_points?: number; top_3_percentage?: string; top_3_points?: number; top_3_position?: number; total_points?: number; }[]`\n\n### Example\n\n```typescript\nimport LsTest from 'leadsnap-test-mcp';\n\nconst client = new LsTest();\n\nconst response = await client.public.api.v1.heatmap.retrieveHeatmapCompetitors(1482);\n\nconsole.log(response);\n```",
|
|
188
|
+
perLanguage: {
|
|
189
|
+
typescript: {
|
|
190
|
+
method: 'client.public.api.v1.heatmap.retrieveHeatmapCompetitors',
|
|
191
|
+
example: "import LsTest from 'leadsnap-test-mcp';\n\nconst client = new LsTest({\n bearerToken: process.env['THRIVE_MCP_BEARER_TOKEN'], // This is the default and can be omitted\n});\n\nconst response = await client.public.api.v1.heatmap.retrieveHeatmapCompetitors(1482);\n\nconsole.log(response);",
|
|
192
|
+
},
|
|
193
|
+
http: {
|
|
194
|
+
example: 'curl https://app.leadsnap.com/public/api/v1/heatmaps/$HEATMAP/competitors \\\n -H "Authorization: Bearer $THRIVE_MCP_BEARER_TOKEN"',
|
|
195
|
+
},
|
|
196
|
+
},
|
|
197
|
+
},
|
|
198
|
+
{
|
|
199
|
+
name: 'list_schedules',
|
|
200
|
+
endpoint: '/public/api/v1/heatmap/schedules',
|
|
201
|
+
httpMethod: 'get',
|
|
202
|
+
summary: 'List schedules',
|
|
203
|
+
description: 'Returns a paginated list of heatmap schedules for the account. Supports filtering, sorting, searching, and pagination.\n\n**Pagination** — all list responses include pagination fields at the root level alongside `data`:\n- `total` total matching records; `last_page` total pages; `per_page` results per page (default 25)\n- `next_page_url` URL of the next page (`null` on the last page)\n- `links` array of page link objects (`url`, `label`, `active`)\n\n**Date filters** — date params accept an object with `start_date` and/or `end_date` (YYYY-MM-DD):\n```\nfilter[created_at][start_date]=2026-01-01\nfilter[created_at][end_date]=2026-04-30\n```\nNamed range aliases are also supported via `filter[created_at][date_range]`:\n`today`, `yesterday`, `last_7_days`, `last_30_days`, `this_month`, `last_month`, `this_year`, `last_year`, `all_time`',
|
|
204
|
+
stainlessPath: '(resource) public.api.v1.heatmap.schedules > (method) list_schedules',
|
|
205
|
+
qualified: 'client.public.api.v1.heatmap.schedules.listSchedules',
|
|
206
|
+
params: [
|
|
207
|
+
'filter[company_id]?: number;',
|
|
208
|
+
'filter[created_at][end_date]?: string;',
|
|
209
|
+
'filter[created_at][start_date]?: string;',
|
|
210
|
+
'filter[google_place_id]?: string;',
|
|
211
|
+
'filter[keyword]?: string;',
|
|
212
|
+
'filter[location_id]?: number;',
|
|
213
|
+
'filter[name]?: string;',
|
|
214
|
+
'filter[place_id]?: number;',
|
|
215
|
+
'filter[repeat_every]?: number;',
|
|
216
|
+
'filter[repeat_on]?: number;',
|
|
217
|
+
'filter[repeat_type]?: string;',
|
|
218
|
+
'filter[status]?: string;',
|
|
219
|
+
'page?: number;',
|
|
220
|
+
'per_page?: number;',
|
|
221
|
+
'search?: string;',
|
|
222
|
+
'sort?: string;',
|
|
223
|
+
],
|
|
224
|
+
response: '{ current_page?: number; data?: { id?: number; draw_type?: string; google_location?: string; grid_points?: object[]; grid_size?: number; keywords?: string[]; lat?: string; lead_source_id?: string; length_unit?: string; lng?: string; name?: string; place?: object; place_id?: number; radius?: number; schedule_config?: object; status?: string; stop_reason?: string; zoom_level?: string; }[]; first_page_url?: string; from?: number; last_page?: number; last_page_url?: string; links?: { active?: boolean; label?: string; url?: string; }[]; next_page_url?: string; path?: string; per_page?: number; prev_page_url?: string; to?: number; total?: number; }',
|
|
225
|
+
markdown: "## list_schedules\n\n`client.public.api.v1.heatmap.schedules.listSchedules(filter[company_id]?: number, filter[created_at][end_date]?: string, filter[created_at][start_date]?: string, filter[google_place_id]?: string, filter[keyword]?: string, filter[location_id]?: number, filter[name]?: string, filter[place_id]?: number, filter[repeat_every]?: number, filter[repeat_on]?: number, filter[repeat_type]?: string, filter[status]?: string, page?: number, per_page?: number, search?: string, sort?: string): { current_page?: number; data?: object[]; first_page_url?: string; from?: number; last_page?: number; last_page_url?: string; links?: object[]; next_page_url?: string; path?: string; per_page?: number; prev_page_url?: string; to?: number; total?: number; }`\n\n**get** `/public/api/v1/heatmap/schedules`\n\nReturns a paginated list of heatmap schedules for the account. Supports filtering, sorting, searching, and pagination.\n\n**Pagination** — all list responses include pagination fields at the root level alongside `data`:\n- `total` total matching records; `last_page` total pages; `per_page` results per page (default 25)\n- `next_page_url` URL of the next page (`null` on the last page)\n- `links` array of page link objects (`url`, `label`, `active`)\n\n**Date filters** — date params accept an object with `start_date` and/or `end_date` (YYYY-MM-DD):\n```\nfilter[created_at][start_date]=2026-01-01\nfilter[created_at][end_date]=2026-04-30\n```\nNamed range aliases are also supported via `filter[created_at][date_range]`:\n`today`, `yesterday`, `last_7_days`, `last_30_days`, `this_month`, `last_month`, `this_year`, `last_year`, `all_time`\n\n### Parameters\n\n- `filter[company_id]?: number`\n Filter by lead source / company ID.\n\n- `filter[created_at][end_date]?: string`\n Filter by creation date — range end (YYYY-MM-DD).\n\n- `filter[created_at][start_date]?: string`\n Filter by creation date — range start (YYYY-MM-DD).\n\n- `filter[google_place_id]?: string`\n Filter by Google Place ID (exact).\n\n- `filter[keyword]?: string`\n Filter by keyword in the schedule (exact match).\n\n- `filter[location_id]?: number`\n Filter by location ID.\n\n- `filter[name]?: string`\n Filter by schedule name (partial match).\n\n- `filter[place_id]?: number`\n Filter by place ID.\n\n- `filter[repeat_every]?: number`\n Filter by repeat interval.\n\n- `filter[repeat_on]?: number`\n Filter by day of week (1–7) or day of month (1–31) depending on repeat_type.\n\n- `filter[repeat_type]?: string`\n Filter by repeat type. Accepted: `week`, `month`, `custom-day`, `custom-week`, `custom-month`.\n\n- `filter[status]?: string`\n Filter by schedule status. Accepted: `active`, `paused`.\n\n- `page?: number`\n Page number.\n\n- `per_page?: number`\n Number of results per page (default 25).\n\n- `search?: string`\n Full-text search across schedule name and place name.\n\n- `sort?: string`\n Sort field. Prefix with `-` for descending. Accepted: `created_at`, `name`, `status`, `scheduled_at`, `last_schedule_ran_at`, `repeat_type`, `repeat_every`, `place_id`, `place.name`, `location_id`.\n\n### Returns\n\n- `{ current_page?: number; data?: { id?: number; draw_type?: string; google_location?: string; grid_points?: { lat?: string; lng?: string; }[]; grid_size?: number; keywords?: string[]; lat?: string; lead_source_id?: string; length_unit?: string; lng?: string; name?: string; place?: { id?: number; address?: string; ave_review_rating?: number; feature_id?: string; google_place_id?: string; google_place_serial?: string; latitude?: string; longitude?: string; main_category?: string; map_url?: string; name?: string; phone?: string; place_url?: string; ranking?: string; related_categories?: string[]; review_count?: number; thumbnail_url?: string; website_url?: string; }; place_id?: number; radius?: number; schedule_config?: { id?: number; ai_recurring?: number; created_at?: string; delete_oldpost_on_recurring?: number; is_recurring?: number; last_schedule_ran_at?: string; recurring_count?: number; repeat_every?: number; repeat_on?: string; repeat_type?: string; scheduled_at?: string; status?: string; stop_reason?: string; timezone?: string; updated_at?: string; }; status?: string; stop_reason?: string; zoom_level?: string; }[]; first_page_url?: string; from?: number; last_page?: number; last_page_url?: string; links?: { active?: boolean; label?: string; url?: string; }[]; next_page_url?: string; path?: string; per_page?: number; prev_page_url?: string; to?: number; total?: number; }`\n\n - `current_page?: number`\n - `data?: { id?: number; draw_type?: string; google_location?: string; grid_points?: { lat?: string; lng?: string; }[]; grid_size?: number; keywords?: string[]; lat?: string; lead_source_id?: string; length_unit?: string; lng?: string; name?: string; place?: { id?: number; address?: string; ave_review_rating?: number; feature_id?: string; google_place_id?: string; google_place_serial?: string; latitude?: string; longitude?: string; main_category?: string; map_url?: string; name?: string; phone?: string; place_url?: string; ranking?: string; related_categories?: string[]; review_count?: number; thumbnail_url?: string; website_url?: string; }; place_id?: number; radius?: number; schedule_config?: { id?: number; ai_recurring?: number; created_at?: string; delete_oldpost_on_recurring?: number; is_recurring?: number; last_schedule_ran_at?: string; recurring_count?: number; repeat_every?: number; repeat_on?: string; repeat_type?: string; scheduled_at?: string; status?: string; stop_reason?: string; timezone?: string; updated_at?: string; }; status?: string; stop_reason?: string; zoom_level?: string; }[]`\n - `first_page_url?: string`\n - `from?: number`\n - `last_page?: number`\n - `last_page_url?: string`\n - `links?: { active?: boolean; label?: string; url?: string; }[]`\n - `next_page_url?: string`\n - `path?: string`\n - `per_page?: number`\n - `prev_page_url?: string`\n - `to?: number`\n - `total?: number`\n\n### Example\n\n```typescript\nimport LsTest from 'leadsnap-test-mcp';\n\nconst client = new LsTest();\n\nconst response = await client.public.api.v1.heatmap.schedules.listSchedules();\n\nconsole.log(response);\n```",
|
|
226
|
+
perLanguage: {
|
|
227
|
+
typescript: {
|
|
228
|
+
method: 'client.public.api.v1.heatmap.schedules.listSchedules',
|
|
229
|
+
example: "import LsTest from 'leadsnap-test-mcp';\n\nconst client = new LsTest({\n bearerToken: process.env['THRIVE_MCP_BEARER_TOKEN'], // This is the default and can be omitted\n});\n\nconst response = await client.public.api.v1.heatmap.schedules.listSchedules();\n\nconsole.log(response.current_page);",
|
|
230
|
+
},
|
|
231
|
+
http: {
|
|
232
|
+
example: 'curl https://app.leadsnap.com/public/api/v1/heatmap/schedules \\\n -H "Authorization: Bearer $THRIVE_MCP_BEARER_TOKEN"',
|
|
233
|
+
},
|
|
234
|
+
},
|
|
235
|
+
},
|
|
236
|
+
{
|
|
237
|
+
name: 'create_schedule',
|
|
238
|
+
endpoint: '/public/api/v1/heatmap/schedules',
|
|
239
|
+
httpMethod: 'post',
|
|
240
|
+
summary: 'Create schedule',
|
|
241
|
+
description: 'Creates a new automated heatmap schedule. The schedule will run heatmaps on the specified recurrence.',
|
|
242
|
+
stainlessPath: '(resource) public.api.v1.heatmap.schedules > (method) create_schedule',
|
|
243
|
+
qualified: 'client.public.api.v1.heatmap.schedules.createSchedule',
|
|
244
|
+
params: [
|
|
245
|
+
'heatmap_config: { grid_points: { lat: number; lng: number; }[]; keywords: string[]; name: string; place_id: number; lat?: number; lead_source_id?: number; lng?: number; location_id?: number; };',
|
|
246
|
+
'schedule_config: { repeat_type: string; repeat_every?: number; repeat_on?: number; schedule_hour_minute?: string; timezone?: string; };',
|
|
247
|
+
],
|
|
248
|
+
response: '{ id?: number; draw_type?: string; google_location?: string; grid_points?: { lat?: number; lng?: number; }[]; grid_size?: number; keywords?: string[]; lat?: number; lead_source_id?: string; length_unit?: string; lng?: number; name?: string; place?: { id?: number; address?: string; ave_review_rating?: number; feature_id?: string; google_place_id?: string; google_place_serial?: string; latitude?: string; longitude?: string; main_category?: string; map_url?: string; name?: string; phone?: string; place_url?: string; ranking?: string; related_categories?: string[]; review_count?: number; thumbnail_url?: string; website_url?: string; }; place_id?: number; radius?: number; schedule_config?: { id?: number; ai_recurring?: number; created_at?: string; delete_oldpost_on_recurring?: number; is_recurring?: number; last_schedule_ran_at?: string; recurring_count?: number; repeat_every?: number; repeat_on?: string; repeat_type?: string; scheduled_at?: string; status?: string; stop_reason?: string; timezone?: string; updated_at?: string; }; status?: string; stop_reason?: string; zoom_level?: string; }',
|
|
249
|
+
markdown: "## create_schedule\n\n`client.public.api.v1.heatmap.schedules.createSchedule(heatmap_config: { grid_points: { lat: number; lng: number; }[]; keywords: string[]; name: string; place_id: number; lat?: number; lead_source_id?: number; lng?: number; location_id?: number; }, schedule_config: { repeat_type: string; repeat_every?: number; repeat_on?: number; schedule_hour_minute?: string; timezone?: string; }): { id?: number; draw_type?: string; google_location?: string; grid_points?: object[]; grid_size?: number; keywords?: string[]; lat?: number; lead_source_id?: string; length_unit?: string; lng?: number; name?: string; place?: object; place_id?: number; radius?: number; schedule_config?: object; status?: string; stop_reason?: string; zoom_level?: string; }`\n\n**post** `/public/api/v1/heatmap/schedules`\n\nCreates a new automated heatmap schedule. The schedule will run heatmaps on the specified recurrence.\n\n### Parameters\n\n- `heatmap_config: { grid_points: { lat: number; lng: number; }[]; keywords: string[]; name: string; place_id: number; lat?: number; lead_source_id?: number; lng?: number; location_id?: number; }`\n Grid and place configuration for the heatmap.\n - `grid_points: { lat: number; lng: number; }[]`\n Pre-computed grid point coordinates (min 1, max 169). Use the [Generate grid points](#tag/Heatmap-Points/POST/public/api/v1/heatmap/grid-points) endpoint to compute these from a grid config.\n - `keywords: string[]`\n Keywords to search.\n - `name: string`\n Schedule name.\n - `place_id: number`\n The heatmap place ID.\n - `lat?: number`\n optional Grid center latitude (informational).\n - `lead_source_id?: number`\n optional Lead source / company ID.\n - `lng?: number`\n optional Grid center longitude (informational).\n - `location_id?: number`\n optional Location ID to associate the schedule with.\n\n- `schedule_config: { repeat_type: string; repeat_every?: number; repeat_on?: number; schedule_hour_minute?: string; timezone?: string; }`\n Recurrence settings for the schedule.\n - `repeat_type: string`\n Recurrence pattern. Each value has different requirements for `repeat_every` and `repeat_on`:<br><br>\n- `week` — runs once a week on a fixed day. **Requires** `repeat_on` (1=Monday … 7=Sunday). `repeat_every` is ignored.<br>\n _Example: run every Monday → `repeat_type: \"week\", repeat_on: 1`_<br><br>\n- `month` — runs once a month on a fixed calendar day. **Requires** `repeat_on` (1–31). `repeat_every` is ignored.<br>\n _Example: run on the 15th of every month → `repeat_type: \"month\", repeat_on: 15`_<br><br>\n- `custom-day` — runs every N days. **Requires** `repeat_every` (≥ 1). `repeat_on` is ignored.<br>\n _Example: run every 3 days → `repeat_type: \"custom-day\", repeat_every: 3`_<br><br>\n- `custom-week` — runs every N weeks. **Requires** `repeat_every` (≥ 1). `repeat_on` is ignored.<br>\n _Example: run every 2 weeks → `repeat_type: \"custom-week\", repeat_every: 2`_<br><br>\n- `custom-month` — runs every N months. **Requires** `repeat_every` (≥ 1). `repeat_on` is ignored.<br>\n _Example: run every 6 months → `repeat_type: \"custom-month\", repeat_every: 6`_\n - `repeat_every?: number`\n optional Required when `repeat_type` is `custom-day`, `custom-week`, or `custom-month`. Specifies the interval between runs (minimum 1). Ignored for `week` and `month`.\n - `repeat_on?: number`\n optional Required when `repeat_type` is `week` or `month`. For `week`: day of the week where 1=Monday and 7=Sunday. For `month`: day of the calendar month (1–31). Ignored for `custom-*` types.\n - `schedule_hour_minute?: string`\n optional Time of day to run the schedule in `HH:MM` 24-hour format. Defaults to `12:00`.\n - `timezone?: string`\n optional Timezone for the schedule. Accepts an IANA timezone name (e.g. `America/Chicago`) or a UTC offset (e.g. `+02:00`). Defaults to `UTC`.\n\n### Returns\n\n- `{ id?: number; draw_type?: string; google_location?: string; grid_points?: { lat?: number; lng?: number; }[]; grid_size?: number; keywords?: string[]; lat?: number; lead_source_id?: string; length_unit?: string; lng?: number; name?: string; place?: { id?: number; address?: string; ave_review_rating?: number; feature_id?: string; google_place_id?: string; google_place_serial?: string; latitude?: string; longitude?: string; main_category?: string; map_url?: string; name?: string; phone?: string; place_url?: string; ranking?: string; related_categories?: string[]; review_count?: number; thumbnail_url?: string; website_url?: string; }; place_id?: number; radius?: number; schedule_config?: { id?: number; ai_recurring?: number; created_at?: string; delete_oldpost_on_recurring?: number; is_recurring?: number; last_schedule_ran_at?: string; recurring_count?: number; repeat_every?: number; repeat_on?: string; repeat_type?: string; scheduled_at?: string; status?: string; stop_reason?: string; timezone?: string; updated_at?: string; }; status?: string; stop_reason?: string; zoom_level?: string; }`\n\n - `id?: number`\n - `draw_type?: string`\n - `google_location?: string`\n - `grid_points?: { lat?: number; lng?: number; }[]`\n - `grid_size?: number`\n - `keywords?: string[]`\n - `lat?: number`\n - `lead_source_id?: string`\n - `length_unit?: string`\n - `lng?: number`\n - `name?: string`\n - `place?: { id?: number; address?: string; ave_review_rating?: number; feature_id?: string; google_place_id?: string; google_place_serial?: string; latitude?: string; longitude?: string; main_category?: string; map_url?: string; name?: string; phone?: string; place_url?: string; ranking?: string; related_categories?: string[]; review_count?: number; thumbnail_url?: string; website_url?: string; }`\n - `place_id?: number`\n - `radius?: number`\n - `schedule_config?: { id?: number; ai_recurring?: number; created_at?: string; delete_oldpost_on_recurring?: number; is_recurring?: number; last_schedule_ran_at?: string; recurring_count?: number; repeat_every?: number; repeat_on?: string; repeat_type?: string; scheduled_at?: string; status?: string; stop_reason?: string; timezone?: string; updated_at?: string; }`\n - `status?: string`\n - `stop_reason?: string`\n - `zoom_level?: string`\n\n### Example\n\n```typescript\nimport LsTest from 'leadsnap-test-mcp';\n\nconst client = new LsTest();\n\nconst response = await client.public.api.v1.heatmap.schedules.createSchedule({\n heatmap_config: {\n grid_points: [{ lat: 28.174798245111, lng: -81.429216072674 }, { lat: 28.174798245111, lng: -81.457292244549 }, { lat: 28.198987716187, lng: -81.401139900799 }, { lat: 28.198987716187, lng: -81.429216072674 }, { lat: 28.198987716187, lng: -81.457292244549 }],\n keywords: ['Plumbing', 'general contractor', 'electrician', 'hvac'],\n name: 'Weekly Roofing Check',\n place_id: 2795512,\n},\n schedule_config: { repeat_type: 'custom-month' },\n});\n\nconsole.log(response);\n```",
|
|
250
|
+
perLanguage: {
|
|
251
|
+
typescript: {
|
|
252
|
+
method: 'client.public.api.v1.heatmap.schedules.createSchedule',
|
|
253
|
+
example: "import LsTest from 'leadsnap-test-mcp';\n\nconst client = new LsTest({\n bearerToken: process.env['THRIVE_MCP_BEARER_TOKEN'], // This is the default and can be omitted\n});\n\nconst response = await client.public.api.v1.heatmap.schedules.createSchedule({\n heatmap_config: {\n grid_points: [\n { lat: 28.174798245111, lng: -81.429216072674 },\n { lat: 28.174798245111, lng: -81.457292244549 },\n { lat: 28.198987716187, lng: -81.401139900799 },\n { lat: 28.198987716187, lng: -81.429216072674 },\n { lat: 28.198987716187, lng: -81.457292244549 },\n ],\n keywords: ['Plumbing', 'general contractor', 'electrician', 'hvac'],\n name: 'Weekly Roofing Check',\n place_id: 2795512,\n },\n schedule_config: { repeat_type: 'custom-month' },\n});\n\nconsole.log(response.id);",
|
|
254
|
+
},
|
|
255
|
+
http: {
|
|
256
|
+
example: 'curl https://app.leadsnap.com/public/api/v1/heatmap/schedules \\\n -H \'Content-Type: application/json\' \\\n -H "Authorization: Bearer $THRIVE_MCP_BEARER_TOKEN" \\\n -d \'{\n "heatmap_config": {\n "grid_points": [\n {\n "lat": 28.174798245111,\n "lng": -81.429216072674\n },\n {\n "lat": 28.174798245111,\n "lng": -81.457292244549\n },\n {\n "lat": 28.198987716187,\n "lng": -81.401139900799\n },\n {\n "lat": 28.198987716187,\n "lng": -81.429216072674\n },\n {\n "lat": 28.198987716187,\n "lng": -81.457292244549\n }\n ],\n "keywords": [\n "Plumbing",\n "general contractor",\n "electrician",\n "hvac"\n ],\n "name": "Weekly Roofing Check",\n "place_id": 2795512,\n "lat": 28.301844298972,\n "lng": -81.485368416424\n },\n "schedule_config": {\n "repeat_type": "custom-month",\n "repeat_every": 5,\n "schedule_hour_minute": "05:00",\n "timezone": "+02:00"\n }\n }\'',
|
|
257
|
+
},
|
|
258
|
+
},
|
|
259
|
+
},
|
|
260
|
+
{
|
|
261
|
+
name: 'retrieve_schedule',
|
|
262
|
+
endpoint: '/public/api/v1/heatmap/schedules/{schedule}',
|
|
263
|
+
httpMethod: 'get',
|
|
264
|
+
summary: 'Get schedule',
|
|
265
|
+
description: 'Returns full details of a single heatmap schedule including its configuration and next run time.',
|
|
266
|
+
stainlessPath: '(resource) public.api.v1.heatmap.schedules > (method) retrieve_schedule',
|
|
267
|
+
qualified: 'client.public.api.v1.heatmap.schedules.retrieveSchedule',
|
|
268
|
+
params: ['schedule: number;'],
|
|
269
|
+
response: '{ id?: number; draw_type?: string; google_location?: string; grid_points?: { lat?: string; lng?: string; }[]; grid_size?: number; keywords?: string[]; lat?: string; lead_source_id?: string; length_unit?: string; lng?: string; name?: string; place?: { id?: number; address?: string; ave_review_rating?: number; feature_id?: string; google_place_id?: string; google_place_serial?: string; latitude?: string; longitude?: string; main_category?: string; map_url?: string; name?: string; phone?: string; place_url?: string; ranking?: string; related_categories?: string[]; review_count?: number; thumbnail_url?: string; website_url?: string; }; place_id?: number; radius?: number; schedule_config?: { id?: number; ai_recurring?: number; created_at?: string; delete_oldpost_on_recurring?: number; is_recurring?: number; last_schedule_ran_at?: string; recurring_count?: number; repeat_every?: number; repeat_on?: string; repeat_type?: string; scheduled_at?: string; status?: string; stop_reason?: string; timezone?: string; updated_at?: string; }; status?: string; stop_reason?: string; zoom_level?: string; }',
|
|
270
|
+
markdown: "## retrieve_schedule\n\n`client.public.api.v1.heatmap.schedules.retrieveSchedule(schedule: number): { id?: number; draw_type?: string; google_location?: string; grid_points?: object[]; grid_size?: number; keywords?: string[]; lat?: string; lead_source_id?: string; length_unit?: string; lng?: string; name?: string; place?: object; place_id?: number; radius?: number; schedule_config?: object; status?: string; stop_reason?: string; zoom_level?: string; }`\n\n**get** `/public/api/v1/heatmap/schedules/{schedule}`\n\nReturns full details of a single heatmap schedule including its configuration and next run time.\n\n### Parameters\n\n- `schedule: number`\n\n### Returns\n\n- `{ id?: number; draw_type?: string; google_location?: string; grid_points?: { lat?: string; lng?: string; }[]; grid_size?: number; keywords?: string[]; lat?: string; lead_source_id?: string; length_unit?: string; lng?: string; name?: string; place?: { id?: number; address?: string; ave_review_rating?: number; feature_id?: string; google_place_id?: string; google_place_serial?: string; latitude?: string; longitude?: string; main_category?: string; map_url?: string; name?: string; phone?: string; place_url?: string; ranking?: string; related_categories?: string[]; review_count?: number; thumbnail_url?: string; website_url?: string; }; place_id?: number; radius?: number; schedule_config?: { id?: number; ai_recurring?: number; created_at?: string; delete_oldpost_on_recurring?: number; is_recurring?: number; last_schedule_ran_at?: string; recurring_count?: number; repeat_every?: number; repeat_on?: string; repeat_type?: string; scheduled_at?: string; status?: string; stop_reason?: string; timezone?: string; updated_at?: string; }; status?: string; stop_reason?: string; zoom_level?: string; }`\n\n - `id?: number`\n - `draw_type?: string`\n - `google_location?: string`\n - `grid_points?: { lat?: string; lng?: string; }[]`\n - `grid_size?: number`\n - `keywords?: string[]`\n - `lat?: string`\n - `lead_source_id?: string`\n - `length_unit?: string`\n - `lng?: string`\n - `name?: string`\n - `place?: { id?: number; address?: string; ave_review_rating?: number; feature_id?: string; google_place_id?: string; google_place_serial?: string; latitude?: string; longitude?: string; main_category?: string; map_url?: string; name?: string; phone?: string; place_url?: string; ranking?: string; related_categories?: string[]; review_count?: number; thumbnail_url?: string; website_url?: string; }`\n - `place_id?: number`\n - `radius?: number`\n - `schedule_config?: { id?: number; ai_recurring?: number; created_at?: string; delete_oldpost_on_recurring?: number; is_recurring?: number; last_schedule_ran_at?: string; recurring_count?: number; repeat_every?: number; repeat_on?: string; repeat_type?: string; scheduled_at?: string; status?: string; stop_reason?: string; timezone?: string; updated_at?: string; }`\n - `status?: string`\n - `stop_reason?: string`\n - `zoom_level?: string`\n\n### Example\n\n```typescript\nimport LsTest from 'leadsnap-test-mcp';\n\nconst client = new LsTest();\n\nconst response = await client.public.api.v1.heatmap.schedules.retrieveSchedule(10);\n\nconsole.log(response);\n```",
|
|
271
|
+
perLanguage: {
|
|
272
|
+
typescript: {
|
|
273
|
+
method: 'client.public.api.v1.heatmap.schedules.retrieveSchedule',
|
|
274
|
+
example: "import LsTest from 'leadsnap-test-mcp';\n\nconst client = new LsTest({\n bearerToken: process.env['THRIVE_MCP_BEARER_TOKEN'], // This is the default and can be omitted\n});\n\nconst response = await client.public.api.v1.heatmap.schedules.retrieveSchedule(10);\n\nconsole.log(response.id);",
|
|
275
|
+
},
|
|
276
|
+
http: {
|
|
277
|
+
example: 'curl https://app.leadsnap.com/public/api/v1/heatmap/schedules/$SCHEDULE \\\n -H "Authorization: Bearer $THRIVE_MCP_BEARER_TOKEN"',
|
|
278
|
+
},
|
|
279
|
+
},
|
|
280
|
+
},
|
|
281
|
+
{
|
|
282
|
+
name: 'update_schedule',
|
|
283
|
+
endpoint: '/public/api/v1/heatmap/schedules/{schedule_id}',
|
|
284
|
+
httpMethod: 'patch',
|
|
285
|
+
summary: 'Update schedule',
|
|
286
|
+
description: 'Updates the grid configuration and/or recurrence settings of an existing schedule.',
|
|
287
|
+
stainlessPath: '(resource) public.api.v1.heatmap.schedules > (method) update_schedule',
|
|
288
|
+
qualified: 'client.public.api.v1.heatmap.schedules.updateSchedule',
|
|
289
|
+
params: [
|
|
290
|
+
'schedule_id: number;',
|
|
291
|
+
'heatmap_config: { name: string; place_id: number; grid_points?: object[]; keywords?: string[]; };',
|
|
292
|
+
'schedule_config: { repeat_type: string; repeat_on?: number; };',
|
|
293
|
+
],
|
|
294
|
+
response: '{ id?: number; draw_type?: string; google_location?: string; grid_points?: { lat?: number; lng?: number; }[]; grid_size?: number; keywords?: string[]; lat?: number; lead_source_id?: string; length_unit?: string; lng?: number; name?: string; place?: { id?: number; address?: string; ave_review_rating?: number; feature_id?: string; google_place_id?: string; google_place_serial?: string; latitude?: string; longitude?: string; main_category?: string; map_url?: string; name?: string; phone?: string; place_url?: string; ranking?: string; related_categories?: string[]; review_count?: number; thumbnail_url?: string; website_url?: string; }; place_id?: number; radius?: number; schedule_config?: { id?: number; ai_recurring?: number; created_at?: string; delete_oldpost_on_recurring?: number; is_recurring?: number; last_schedule_ran_at?: string; recurring_count?: number; repeat_every?: number; repeat_on?: number; repeat_type?: string; scheduled_at?: string; status?: string; stop_reason?: string; timezone?: string; updated_at?: string; }; status?: string; stop_reason?: string; zoom_level?: string; }',
|
|
295
|
+
markdown: "## update_schedule\n\n`client.public.api.v1.heatmap.schedules.updateSchedule(schedule_id: number, heatmap_config: { name: string; place_id: number; grid_points?: object[]; keywords?: string[]; }, schedule_config: { repeat_type: string; repeat_on?: number; }): { id?: number; draw_type?: string; google_location?: string; grid_points?: object[]; grid_size?: number; keywords?: string[]; lat?: number; lead_source_id?: string; length_unit?: string; lng?: number; name?: string; place?: object; place_id?: number; radius?: number; schedule_config?: object; status?: string; stop_reason?: string; zoom_level?: string; }`\n\n**patch** `/public/api/v1/heatmap/schedules/{schedule_id}`\n\nUpdates the grid configuration and/or recurrence settings of an existing schedule.\n\n### Parameters\n\n- `schedule_id: number`\n\n- `heatmap_config: { name: string; place_id: number; grid_points?: object[]; keywords?: string[]; }`\n Updated grid and place configuration.\n - `name: string`\n Schedule name.\n - `place_id: number`\n The heatmap place ID.\n - `grid_points?: object[]`\n optional Updated grid point coordinates, max 169 (omit to keep existing). Use the [Generate grid points](#tag/Heatmap-Points/POST/public/api/v1/heatmap/grid-points) endpoint to compute these from a grid config.\n - `keywords?: string[]`\n optional Keywords to search (omit to keep existing).\n\n- `schedule_config: { repeat_type: string; repeat_on?: number; }`\n Updated recurrence settings.\n - `repeat_type: string`\n Recurrence type. Accepted: `week`, `month`, `custom-day`, `custom-week`, `custom-month`.\n - `repeat_on?: number`\n optional Day of week (1–7) or day of month (1–31).\n\n### Returns\n\n- `{ id?: number; draw_type?: string; google_location?: string; grid_points?: { lat?: number; lng?: number; }[]; grid_size?: number; keywords?: string[]; lat?: number; lead_source_id?: string; length_unit?: string; lng?: number; name?: string; place?: { id?: number; address?: string; ave_review_rating?: number; feature_id?: string; google_place_id?: string; google_place_serial?: string; latitude?: string; longitude?: string; main_category?: string; map_url?: string; name?: string; phone?: string; place_url?: string; ranking?: string; related_categories?: string[]; review_count?: number; thumbnail_url?: string; website_url?: string; }; place_id?: number; radius?: number; schedule_config?: { id?: number; ai_recurring?: number; created_at?: string; delete_oldpost_on_recurring?: number; is_recurring?: number; last_schedule_ran_at?: string; recurring_count?: number; repeat_every?: number; repeat_on?: number; repeat_type?: string; scheduled_at?: string; status?: string; stop_reason?: string; timezone?: string; updated_at?: string; }; status?: string; stop_reason?: string; zoom_level?: string; }`\n\n - `id?: number`\n - `draw_type?: string`\n - `google_location?: string`\n - `grid_points?: { lat?: number; lng?: number; }[]`\n - `grid_size?: number`\n - `keywords?: string[]`\n - `lat?: number`\n - `lead_source_id?: string`\n - `length_unit?: string`\n - `lng?: number`\n - `name?: string`\n - `place?: { id?: number; address?: string; ave_review_rating?: number; feature_id?: string; google_place_id?: string; google_place_serial?: string; latitude?: string; longitude?: string; main_category?: string; map_url?: string; name?: string; phone?: string; place_url?: string; ranking?: string; related_categories?: string[]; review_count?: number; thumbnail_url?: string; website_url?: string; }`\n - `place_id?: number`\n - `radius?: number`\n - `schedule_config?: { id?: number; ai_recurring?: number; created_at?: string; delete_oldpost_on_recurring?: number; is_recurring?: number; last_schedule_ran_at?: string; recurring_count?: number; repeat_every?: number; repeat_on?: number; repeat_type?: string; scheduled_at?: string; status?: string; stop_reason?: string; timezone?: string; updated_at?: string; }`\n - `status?: string`\n - `stop_reason?: string`\n - `zoom_level?: string`\n\n### Example\n\n```typescript\nimport LsTest from 'leadsnap-test-mcp';\n\nconst client = new LsTest();\n\nconst response = await client.public.api.v1.heatmap.schedules.updateSchedule(89465, {\n heatmap_config: { name: 'Weekly Roofing Check Updated', place_id: 12 },\n schedule_config: { repeat_type: 'month' },\n});\n\nconsole.log(response);\n```",
|
|
296
|
+
perLanguage: {
|
|
297
|
+
typescript: {
|
|
298
|
+
method: 'client.public.api.v1.heatmap.schedules.updateSchedule',
|
|
299
|
+
example: "import LsTest from 'leadsnap-test-mcp';\n\nconst client = new LsTest({\n bearerToken: process.env['THRIVE_MCP_BEARER_TOKEN'], // This is the default and can be omitted\n});\n\nconst response = await client.public.api.v1.heatmap.schedules.updateSchedule(89465, {\n heatmap_config: { name: 'Weekly Roofing Check Updated', place_id: 12 },\n schedule_config: { repeat_type: 'month' },\n});\n\nconsole.log(response.id);",
|
|
300
|
+
},
|
|
301
|
+
http: {
|
|
302
|
+
example: 'curl https://app.leadsnap.com/public/api/v1/heatmap/schedules/$SCHEDULE_ID \\\n -X PATCH \\\n -H \'Content-Type: application/json\' \\\n -H "Authorization: Bearer $THRIVE_MCP_BEARER_TOKEN" \\\n -d \'{\n "heatmap_config": {\n "name": "Weekly Roofing Check Updated",\n "place_id": 12\n },\n "schedule_config": {\n "repeat_type": "month"\n }\n }\'',
|
|
303
|
+
},
|
|
304
|
+
},
|
|
305
|
+
},
|
|
306
|
+
{
|
|
307
|
+
name: 'pause_schedule',
|
|
308
|
+
endpoint: '/public/api/v1/heatmap/schedules/{schedule_id}/pause',
|
|
309
|
+
httpMethod: 'post',
|
|
310
|
+
summary: 'Pause schedule',
|
|
311
|
+
description: 'Pauses an active schedule so it stops running until resumed.',
|
|
312
|
+
stainlessPath: '(resource) public.api.v1.heatmap.schedules > (method) pause_schedule',
|
|
313
|
+
qualified: 'client.public.api.v1.heatmap.schedules.pauseSchedule',
|
|
314
|
+
params: ['schedule_id: number;'],
|
|
315
|
+
response: '{ id?: number; draw_type?: string; google_location?: string; grid_points?: { lat?: number; lng?: number; }[]; grid_size?: string; keywords?: string[]; lat?: string; lead_source_id?: string; length_unit?: string; lng?: string; name?: string; place?: { id?: number; address?: string; ave_review_rating?: number; feature_id?: string; google_place_id?: string; google_place_serial?: string; latitude?: string; longitude?: string; main_category?: string; map_url?: string; name?: string; phone?: string; place_url?: string; ranking?: string; related_categories?: string[]; review_count?: number; thumbnail_url?: string; website_url?: string; }; place_id?: number; radius?: string; schedule_config?: { id?: number; ai_recurring?: number; created_at?: string; delete_oldpost_on_recurring?: number; is_recurring?: number; last_schedule_ran_at?: string; recurring_count?: number; repeat_every?: number; repeat_on?: string; repeat_type?: string; scheduled_at?: string; status?: string; stop_reason?: string; timezone?: string; updated_at?: string; }; status?: string; stop_reason?: string; zoom_level?: string; }',
|
|
316
|
+
markdown: "## pause_schedule\n\n`client.public.api.v1.heatmap.schedules.pauseSchedule(schedule_id: number): { id?: number; draw_type?: string; google_location?: string; grid_points?: object[]; grid_size?: string; keywords?: string[]; lat?: string; lead_source_id?: string; length_unit?: string; lng?: string; name?: string; place?: object; place_id?: number; radius?: string; schedule_config?: object; status?: string; stop_reason?: string; zoom_level?: string; }`\n\n**post** `/public/api/v1/heatmap/schedules/{schedule_id}/pause`\n\nPauses an active schedule so it stops running until resumed.\n\n### Parameters\n\n- `schedule_id: number`\n\n### Returns\n\n- `{ id?: number; draw_type?: string; google_location?: string; grid_points?: { lat?: number; lng?: number; }[]; grid_size?: string; keywords?: string[]; lat?: string; lead_source_id?: string; length_unit?: string; lng?: string; name?: string; place?: { id?: number; address?: string; ave_review_rating?: number; feature_id?: string; google_place_id?: string; google_place_serial?: string; latitude?: string; longitude?: string; main_category?: string; map_url?: string; name?: string; phone?: string; place_url?: string; ranking?: string; related_categories?: string[]; review_count?: number; thumbnail_url?: string; website_url?: string; }; place_id?: number; radius?: string; schedule_config?: { id?: number; ai_recurring?: number; created_at?: string; delete_oldpost_on_recurring?: number; is_recurring?: number; last_schedule_ran_at?: string; recurring_count?: number; repeat_every?: number; repeat_on?: string; repeat_type?: string; scheduled_at?: string; status?: string; stop_reason?: string; timezone?: string; updated_at?: string; }; status?: string; stop_reason?: string; zoom_level?: string; }`\n\n - `id?: number`\n - `draw_type?: string`\n - `google_location?: string`\n - `grid_points?: { lat?: number; lng?: number; }[]`\n - `grid_size?: string`\n - `keywords?: string[]`\n - `lat?: string`\n - `lead_source_id?: string`\n - `length_unit?: string`\n - `lng?: string`\n - `name?: string`\n - `place?: { id?: number; address?: string; ave_review_rating?: number; feature_id?: string; google_place_id?: string; google_place_serial?: string; latitude?: string; longitude?: string; main_category?: string; map_url?: string; name?: string; phone?: string; place_url?: string; ranking?: string; related_categories?: string[]; review_count?: number; thumbnail_url?: string; website_url?: string; }`\n - `place_id?: number`\n - `radius?: string`\n - `schedule_config?: { id?: number; ai_recurring?: number; created_at?: string; delete_oldpost_on_recurring?: number; is_recurring?: number; last_schedule_ran_at?: string; recurring_count?: number; repeat_every?: number; repeat_on?: string; repeat_type?: string; scheduled_at?: string; status?: string; stop_reason?: string; timezone?: string; updated_at?: string; }`\n - `status?: string`\n - `stop_reason?: string`\n - `zoom_level?: string`\n\n### Example\n\n```typescript\nimport LsTest from 'leadsnap-test-mcp';\n\nconst client = new LsTest();\n\nconst response = await client.public.api.v1.heatmap.schedules.pauseSchedule(10);\n\nconsole.log(response);\n```",
|
|
317
|
+
perLanguage: {
|
|
318
|
+
typescript: {
|
|
319
|
+
method: 'client.public.api.v1.heatmap.schedules.pauseSchedule',
|
|
320
|
+
example: "import LsTest from 'leadsnap-test-mcp';\n\nconst client = new LsTest({\n bearerToken: process.env['THRIVE_MCP_BEARER_TOKEN'], // This is the default and can be omitted\n});\n\nconst response = await client.public.api.v1.heatmap.schedules.pauseSchedule(10);\n\nconsole.log(response.id);",
|
|
321
|
+
},
|
|
322
|
+
http: {
|
|
323
|
+
example: 'curl https://app.leadsnap.com/public/api/v1/heatmap/schedules/$SCHEDULE_ID/pause \\\n -X POST \\\n -H "Authorization: Bearer $THRIVE_MCP_BEARER_TOKEN"',
|
|
324
|
+
},
|
|
325
|
+
},
|
|
326
|
+
},
|
|
327
|
+
{
|
|
328
|
+
name: 'resume_schedule',
|
|
329
|
+
endpoint: '/public/api/v1/heatmap/schedules/{schedule_id}/resume',
|
|
330
|
+
httpMethod: 'post',
|
|
331
|
+
summary: 'Resume schedule',
|
|
332
|
+
description: 'Resumes a paused schedule so it runs again on its next scheduled date.',
|
|
333
|
+
stainlessPath: '(resource) public.api.v1.heatmap.schedules > (method) resume_schedule',
|
|
334
|
+
qualified: 'client.public.api.v1.heatmap.schedules.resumeSchedule',
|
|
335
|
+
params: ['schedule_id: number;'],
|
|
336
|
+
response: '{ id?: number; draw_type?: string; google_location?: string; grid_points?: { lat?: number; lng?: number; }[]; grid_size?: string; keywords?: string[]; lat?: string; lead_source_id?: string; length_unit?: string; lng?: string; name?: string; place?: { id?: number; address?: string; ave_review_rating?: number; feature_id?: string; google_place_id?: string; google_place_serial?: string; latitude?: string; longitude?: string; main_category?: string; map_url?: string; name?: string; phone?: string; place_url?: string; ranking?: string; related_categories?: string[]; review_count?: number; thumbnail_url?: string; website_url?: string; }; place_id?: number; radius?: string; schedule_config?: { id?: number; ai_recurring?: number; created_at?: string; delete_oldpost_on_recurring?: number; is_recurring?: number; last_schedule_ran_at?: string; recurring_count?: number; repeat_every?: number; repeat_on?: string; repeat_type?: string; scheduled_at?: string; status?: string; stop_reason?: string; timezone?: string; updated_at?: string; }; status?: string; stop_reason?: string; zoom_level?: string; }',
|
|
337
|
+
markdown: "## resume_schedule\n\n`client.public.api.v1.heatmap.schedules.resumeSchedule(schedule_id: number): { id?: number; draw_type?: string; google_location?: string; grid_points?: object[]; grid_size?: string; keywords?: string[]; lat?: string; lead_source_id?: string; length_unit?: string; lng?: string; name?: string; place?: object; place_id?: number; radius?: string; schedule_config?: object; status?: string; stop_reason?: string; zoom_level?: string; }`\n\n**post** `/public/api/v1/heatmap/schedules/{schedule_id}/resume`\n\nResumes a paused schedule so it runs again on its next scheduled date.\n\n### Parameters\n\n- `schedule_id: number`\n\n### Returns\n\n- `{ id?: number; draw_type?: string; google_location?: string; grid_points?: { lat?: number; lng?: number; }[]; grid_size?: string; keywords?: string[]; lat?: string; lead_source_id?: string; length_unit?: string; lng?: string; name?: string; place?: { id?: number; address?: string; ave_review_rating?: number; feature_id?: string; google_place_id?: string; google_place_serial?: string; latitude?: string; longitude?: string; main_category?: string; map_url?: string; name?: string; phone?: string; place_url?: string; ranking?: string; related_categories?: string[]; review_count?: number; thumbnail_url?: string; website_url?: string; }; place_id?: number; radius?: string; schedule_config?: { id?: number; ai_recurring?: number; created_at?: string; delete_oldpost_on_recurring?: number; is_recurring?: number; last_schedule_ran_at?: string; recurring_count?: number; repeat_every?: number; repeat_on?: string; repeat_type?: string; scheduled_at?: string; status?: string; stop_reason?: string; timezone?: string; updated_at?: string; }; status?: string; stop_reason?: string; zoom_level?: string; }`\n\n - `id?: number`\n - `draw_type?: string`\n - `google_location?: string`\n - `grid_points?: { lat?: number; lng?: number; }[]`\n - `grid_size?: string`\n - `keywords?: string[]`\n - `lat?: string`\n - `lead_source_id?: string`\n - `length_unit?: string`\n - `lng?: string`\n - `name?: string`\n - `place?: { id?: number; address?: string; ave_review_rating?: number; feature_id?: string; google_place_id?: string; google_place_serial?: string; latitude?: string; longitude?: string; main_category?: string; map_url?: string; name?: string; phone?: string; place_url?: string; ranking?: string; related_categories?: string[]; review_count?: number; thumbnail_url?: string; website_url?: string; }`\n - `place_id?: number`\n - `radius?: string`\n - `schedule_config?: { id?: number; ai_recurring?: number; created_at?: string; delete_oldpost_on_recurring?: number; is_recurring?: number; last_schedule_ran_at?: string; recurring_count?: number; repeat_every?: number; repeat_on?: string; repeat_type?: string; scheduled_at?: string; status?: string; stop_reason?: string; timezone?: string; updated_at?: string; }`\n - `status?: string`\n - `stop_reason?: string`\n - `zoom_level?: string`\n\n### Example\n\n```typescript\nimport LsTest from 'leadsnap-test-mcp';\n\nconst client = new LsTest();\n\nconst response = await client.public.api.v1.heatmap.schedules.resumeSchedule(10);\n\nconsole.log(response);\n```",
|
|
338
|
+
perLanguage: {
|
|
339
|
+
typescript: {
|
|
340
|
+
method: 'client.public.api.v1.heatmap.schedules.resumeSchedule',
|
|
341
|
+
example: "import LsTest from 'leadsnap-test-mcp';\n\nconst client = new LsTest({\n bearerToken: process.env['THRIVE_MCP_BEARER_TOKEN'], // This is the default and can be omitted\n});\n\nconst response = await client.public.api.v1.heatmap.schedules.resumeSchedule(10);\n\nconsole.log(response.id);",
|
|
342
|
+
},
|
|
343
|
+
http: {
|
|
344
|
+
example: 'curl https://app.leadsnap.com/public/api/v1/heatmap/schedules/$SCHEDULE_ID/resume \\\n -X POST \\\n -H "Authorization: Bearer $THRIVE_MCP_BEARER_TOKEN"',
|
|
345
|
+
},
|
|
346
|
+
},
|
|
347
|
+
},
|
|
348
|
+
];
|
|
349
|
+
const EMBEDDED_READMES = [
|
|
350
|
+
{
|
|
351
|
+
language: 'typescript',
|
|
352
|
+
content: "# Ls Test TypeScript API Library\n\n[)](https://npmjs.org/package/leadsnap-test-mcp) \n\nThis library provides convenient access to the Ls Test REST API from server-side TypeScript or JavaScript.\n\n\n\nThe full API of this library can be found in [api.md](api.md).\n\nIt is generated with [Stainless](https://www.stainless.com/).\n\n## MCP Server\n\nUse the Ls Test MCP Server to enable AI assistants to interact with this API, allowing them to explore endpoints, make test requests, and use documentation to help integrate this SDK into your application.\n\n[](https://cursor.com/en-US/install-mcp?name=ls-test-mcp&config=eyJjb21tYW5kIjoibnB4IiwiYXJncyI6WyIteSIsImxzLXRlc3QtbWNwIl0sImVudiI6eyJUSFJJVkVfTUNQX0JFQVJFUl9UT0tFTiI6Ik15IEJlYXJlciBUb2tlbiJ9fQ)\n[](https://vscode.stainless.com/mcp/%7B%22name%22%3A%22ls-test-mcp%22%2C%22command%22%3A%22npx%22%2C%22args%22%3A%5B%22-y%22%2C%22ls-test-mcp%22%5D%2C%22env%22%3A%7B%22THRIVE_MCP_BEARER_TOKEN%22%3A%22My%20Bearer%20Token%22%7D%7D)\n\n> Note: You may need to set environment variables in your MCP client.\n\n## Installation\n\n```sh\nnpm install leadsnap-test-mcp\n```\n\n\n\n## Usage\n\nThe full API of this library can be found in [api.md](api.md).\n\n<!-- prettier-ignore -->\n```js\nimport LsTest from 'leadsnap-test-mcp';\n\nconst client = new LsTest({\n bearerToken: process.env['THRIVE_MCP_BEARER_TOKEN'], // This is the default and can be omitted\n environment: 'Thrive', // or 'Leadsnap' | 'Staging' | 'Local'; defaults to 'Leadsnap'\n});\n\nconst response = await client.public.api.v1.heatmap.generateGridPoints({\n grid_radius: 0,\n grid_size: 0,\n lat: 0,\n lng: 0,\n});\n\nconsole.log(response.count);\n```\n\n\n\n### Request & Response types\n\nThis library includes TypeScript definitions for all request params and response fields. You may import and use them like so:\n\n<!-- prettier-ignore -->\n```ts\nimport LsTest from 'leadsnap-test-mcp';\n\nconst client = new LsTest({\n bearerToken: process.env['THRIVE_MCP_BEARER_TOKEN'], // This is the default and can be omitted\n environment: 'Thrive', // or 'Leadsnap' | 'Staging' | 'Local'; defaults to 'Leadsnap'\n});\n\nconst params: LsTest.Public.API.V1.HeatmapGenerateGridPointsParams = {\n grid_radius: 0,\n grid_size: 0,\n lat: 0,\n lng: 0,\n};\nconst response: LsTest.Public.API.V1.HeatmapGenerateGridPointsResponse =\n await client.public.api.v1.heatmap.generateGridPoints(params);\n```\n\nDocumentation for each method, request param, and response field are available in docstrings and will appear on hover in most modern editors.\n\n\n\n\n\n## Handling errors\n\nWhen the library is unable to connect to the API,\nor if the API returns a non-success status code (i.e., 4xx or 5xx response),\na subclass of `APIError` will be thrown:\n\n<!-- prettier-ignore -->\n```ts\nconst response = await client.public.api.v1.heatmap\n .generateGridPoints({\n grid_radius: 0,\n grid_size: 0,\n lat: 0,\n lng: 0,\n })\n .catch(async (err) => {\n if (err instanceof LsTest.APIError) {\n console.log(err.status); // 400\n console.log(err.name); // BadRequestError\n console.log(err.headers); // {server: 'nginx', ...}\n } else {\n throw err;\n }\n });\n```\n\nError codes are as follows:\n\n| Status Code | Error Type |\n| ----------- | -------------------------- |\n| 400 | `BadRequestError` |\n| 401 | `AuthenticationError` |\n| 403 | `PermissionDeniedError` |\n| 404 | `NotFoundError` |\n| 422 | `UnprocessableEntityError` |\n| 429 | `RateLimitError` |\n| >=500 | `InternalServerError` |\n| N/A | `APIConnectionError` |\n\n### Retries\n\nCertain errors will be automatically retried 2 times by default, with a short exponential backoff.\nConnection errors (for example, due to a network connectivity problem), 408 Request Timeout, 409 Conflict,\n429 Rate Limit, and >=500 Internal errors will all be retried by default.\n\nYou can use the `maxRetries` option to configure or disable this:\n\n<!-- prettier-ignore -->\n```js\n// Configure the default for all requests:\nconst client = new LsTest({\n maxRetries: 0, // default is 2\n});\n\n// Or, configure per-request:\nawait client.public.api.v1.heatmap.generateGridPoints({\n grid_radius: 0,\n grid_size: 0,\n lat: 0,\n lng: 0,\n}, {\n maxRetries: 5,\n});\n```\n\n### Timeouts\n\nRequests time out after 1 minute by default. You can configure this with a `timeout` option:\n\n<!-- prettier-ignore -->\n```ts\n// Configure the default for all requests:\nconst client = new LsTest({\n timeout: 20 * 1000, // 20 seconds (default is 1 minute)\n});\n\n// Override per-request:\nawait client.public.api.v1.heatmap.generateGridPoints({\n grid_radius: 0,\n grid_size: 0,\n lat: 0,\n lng: 0,\n}, {\n timeout: 5 * 1000,\n});\n```\n\nOn timeout, an `APIConnectionTimeoutError` is thrown.\n\nNote that requests which time out will be [retried twice by default](#retries).\n\n\n\n\n\n## Advanced Usage\n\n### Accessing raw Response data (e.g., headers)\n\nThe \"raw\" `Response` returned by `fetch()` can be accessed through the `.asResponse()` method on the `APIPromise` type that all methods return.\nThis method returns as soon as the headers for a successful response are received and does not consume the response body, so you are free to write custom parsing or streaming logic.\n\nYou can also use the `.withResponse()` method to get the raw `Response` along with the parsed data.\nUnlike `.asResponse()` this method consumes the body, returning once it is parsed.\n\n<!-- prettier-ignore -->\n```ts\nconst client = new LsTest();\n\nconst response = await client.public.api.v1.heatmap\n .generateGridPoints({\n grid_radius: 0,\n grid_size: 0,\n lat: 0,\n lng: 0,\n })\n .asResponse();\nconsole.log(response.headers.get('X-My-Header'));\nconsole.log(response.statusText); // access the underlying Response object\n\nconst { data: response, response: raw } = await client.public.api.v1.heatmap\n .generateGridPoints({\n grid_radius: 0,\n grid_size: 0,\n lat: 0,\n lng: 0,\n })\n .withResponse();\nconsole.log(raw.headers.get('X-My-Header'));\nconsole.log(response.count);\n```\n\n### Logging\n\n> [!IMPORTANT]\n> All log messages are intended for debugging only. The format and content of log messages\n> may change between releases.\n\n#### Log levels\n\nThe log level can be configured in two ways:\n\n1. Via the `LS_TEST_LOG` environment variable\n2. Using the `logLevel` client option (overrides the environment variable if set)\n\n```ts\nimport LsTest from 'leadsnap-test-mcp';\n\nconst client = new LsTest({\n logLevel: 'debug', // Show all log messages\n});\n```\n\nAvailable log levels, from most to least verbose:\n\n- `'debug'` - Show debug messages, info, warnings, and errors\n- `'info'` - Show info messages, warnings, and errors\n- `'warn'` - Show warnings and errors (default)\n- `'error'` - Show only errors\n- `'off'` - Disable all logging\n\nAt the `'debug'` level, all HTTP requests and responses are logged, including headers and bodies.\nSome authentication-related headers are redacted, but sensitive data in request and response bodies\nmay still be visible.\n\n#### Custom logger\n\nBy default, this library logs to `globalThis.console`. You can also provide a custom logger.\nMost logging libraries are supported, including [pino](https://www.npmjs.com/package/pino), [winston](https://www.npmjs.com/package/winston), [bunyan](https://www.npmjs.com/package/bunyan), [consola](https://www.npmjs.com/package/consola), [signale](https://www.npmjs.com/package/signale), and [@std/log](https://jsr.io/@std/log). If your logger doesn't work, please open an issue.\n\nWhen providing a custom logger, the `logLevel` option still controls which messages are emitted, messages\nbelow the configured level will not be sent to your logger.\n\n```ts\nimport LsTest from 'leadsnap-test-mcp';\nimport pino from 'pino';\n\nconst logger = pino();\n\nconst client = new LsTest({\n logger: logger.child({ name: 'LsTest' }),\n logLevel: 'debug', // Send all messages to pino, allowing it to filter\n});\n```\n\n### Making custom/undocumented requests\n\nThis library is typed for convenient access to the documented API. If you need to access undocumented\nendpoints, params, or response properties, the library can still be used.\n\n#### Undocumented endpoints\n\nTo make requests to undocumented endpoints, you can use `client.get`, `client.post`, and other HTTP verbs.\nOptions on the client, such as retries, will be respected when making these requests.\n\n```ts\nawait client.post('/some/path', {\n body: { some_prop: 'foo' },\n query: { some_query_arg: 'bar' },\n});\n```\n\n#### Undocumented request params\n\nTo make requests using undocumented parameters, you may use `// @ts-expect-error` on the undocumented\nparameter. This library doesn't validate at runtime that the request matches the type, so any extra values you\nsend will be sent as-is.\n\n```ts\nclient.public.api.v1.heatmap.generateGridPoints({\n // ...\n // @ts-expect-error baz is not yet public\n baz: 'undocumented option',\n});\n```\n\nFor requests with the `GET` verb, any extra params will be in the query, all other requests will send the\nextra param in the body.\n\nIf you want to explicitly send an extra argument, you can do so with the `query`, `body`, and `headers` request\noptions.\n\n#### Undocumented response properties\n\nTo access undocumented response properties, you may access the response object with `// @ts-expect-error` on\nthe response object, or cast the response object to the requisite type. Like the request params, we do not\nvalidate or strip extra properties from the response from the API.\n\n### Customizing the fetch client\n\nBy default, this library expects a global `fetch` function is defined.\n\nIf you want to use a different `fetch` function, you can either polyfill the global:\n\n```ts\nimport fetch from 'my-fetch';\n\nglobalThis.fetch = fetch;\n```\n\nOr pass it to the client:\n\n```ts\nimport LsTest from 'leadsnap-test-mcp';\nimport fetch from 'my-fetch';\n\nconst client = new LsTest({ fetch });\n```\n\n### Fetch options\n\nIf you want to set custom `fetch` options without overriding the `fetch` function, you can provide a `fetchOptions` object when instantiating the client or making a request. (Request-specific options override client options.)\n\n```ts\nimport LsTest from 'leadsnap-test-mcp';\n\nconst client = new LsTest({\n fetchOptions: {\n // `RequestInit` options\n },\n});\n```\n\n#### Configuring proxies\n\nTo modify proxy behavior, you can provide custom `fetchOptions` that add runtime-specific proxy\noptions to requests:\n\n<img src=\"https://raw.githubusercontent.com/stainless-api/sdk-assets/refs/heads/main/node.svg\" align=\"top\" width=\"18\" height=\"21\"> **Node** <sup>[[docs](https://github.com/nodejs/undici/blob/main/docs/docs/api/ProxyAgent.md#example---proxyagent-with-fetch)]</sup>\n\n```ts\nimport LsTest from 'leadsnap-test-mcp';\nimport * as undici from 'undici';\n\nconst proxyAgent = new undici.ProxyAgent('http://localhost:8888');\nconst client = new LsTest({\n fetchOptions: {\n dispatcher: proxyAgent,\n },\n});\n```\n\n<img src=\"https://raw.githubusercontent.com/stainless-api/sdk-assets/refs/heads/main/bun.svg\" align=\"top\" width=\"18\" height=\"21\"> **Bun** <sup>[[docs](https://bun.sh/guides/http/proxy)]</sup>\n\n```ts\nimport LsTest from 'leadsnap-test-mcp';\n\nconst client = new LsTest({\n fetchOptions: {\n proxy: 'http://localhost:8888',\n },\n});\n```\n\n<img src=\"https://raw.githubusercontent.com/stainless-api/sdk-assets/refs/heads/main/deno.svg\" align=\"top\" width=\"18\" height=\"21\"> **Deno** <sup>[[docs](https://docs.deno.com/api/deno/~/Deno.createHttpClient)]</sup>\n\n```ts\nimport LsTest from 'npm:leadsnap-test-mcp';\n\nconst httpClient = Deno.createHttpClient({ proxy: { url: 'http://localhost:8888' } });\nconst client = new LsTest({\n fetchOptions: {\n client: httpClient,\n },\n});\n```\n\n## Frequently Asked Questions\n\n## Semantic versioning\n\nThis package generally follows [SemVer](https://semver.org/spec/v2.0.0.html) conventions, though certain backwards-incompatible changes may be released as minor versions:\n\n1. Changes that only affect static types, without breaking runtime behavior.\n2. Changes to library internals which are technically public but not intended or documented for external use. _(Please open a GitHub issue to let us know if you are relying on such internals.)_\n3. Changes that we do not expect to impact the vast majority of users in practice.\n\nWe take backwards-compatibility seriously and work hard to ensure you can rely on a smooth upgrade experience.\n\nWe are keen for your feedback; please open an [issue](https://www.github.com/karimsamir897/leadsnap-typescript-production/issues) with questions, bugs, or suggestions.\n\n## Requirements\n\nTypeScript >= 4.9 is supported.\n\nThe following runtimes are supported:\n\n- Web browsers (Up-to-date Chrome, Firefox, Safari, Edge, and more)\n- Node.js 20 LTS or later ([non-EOL](https://endoflife.date/nodejs)) versions.\n- Deno v1.28.0 or higher.\n- Bun 1.0 or later.\n- Cloudflare Workers.\n- Vercel Edge Runtime.\n- Jest 28 or greater with the `\"node\"` environment (`\"jsdom\"` is not supported at this time).\n- Nitro v2.6 or greater.\n\nNote that React Native is not supported at this time.\n\nIf you are interested in other runtime environments, please open or upvote an issue on GitHub.\n\n## Contributing\n\nSee [the contributing documentation](./CONTRIBUTING.md).\n",
|
|
353
|
+
},
|
|
354
|
+
];
|
|
355
|
+
const INDEX_OPTIONS = {
|
|
356
|
+
fields: [
|
|
357
|
+
'name',
|
|
358
|
+
'endpoint',
|
|
359
|
+
'summary',
|
|
360
|
+
'description',
|
|
361
|
+
'qualified',
|
|
362
|
+
'stainlessPath',
|
|
363
|
+
'content',
|
|
364
|
+
'sectionContext',
|
|
365
|
+
],
|
|
366
|
+
storeFields: ['kind', '_original'],
|
|
367
|
+
searchOptions: {
|
|
368
|
+
prefix: true,
|
|
369
|
+
fuzzy: 0.1,
|
|
370
|
+
boost: {
|
|
371
|
+
name: 5,
|
|
372
|
+
stainlessPath: 3,
|
|
373
|
+
endpoint: 3,
|
|
374
|
+
qualified: 3,
|
|
375
|
+
summary: 2,
|
|
376
|
+
content: 1,
|
|
377
|
+
description: 1,
|
|
378
|
+
},
|
|
379
|
+
},
|
|
380
|
+
};
|
|
381
|
+
/**
|
|
382
|
+
* Self-contained local search engine backed by MiniSearch.
|
|
383
|
+
* Method data is embedded at SDK build time; prose documents
|
|
384
|
+
* can be loaded from an optional docs directory at runtime.
|
|
385
|
+
*/
|
|
386
|
+
export class LocalDocsSearch {
|
|
387
|
+
methodIndex;
|
|
388
|
+
proseIndex;
|
|
389
|
+
constructor() {
|
|
390
|
+
this.methodIndex = new MiniSearch(INDEX_OPTIONS);
|
|
391
|
+
this.proseIndex = new MiniSearch(INDEX_OPTIONS);
|
|
392
|
+
}
|
|
393
|
+
static async create(opts) {
|
|
394
|
+
const instance = new LocalDocsSearch();
|
|
395
|
+
instance.indexMethods(EMBEDDED_METHODS);
|
|
396
|
+
for (const readme of EMBEDDED_READMES) {
|
|
397
|
+
instance.indexProse(readme.content, `readme:${readme.language}`);
|
|
398
|
+
}
|
|
399
|
+
if (opts?.docsDir) {
|
|
400
|
+
await instance.loadDocsDirectory(opts.docsDir);
|
|
401
|
+
}
|
|
402
|
+
return instance;
|
|
403
|
+
}
|
|
404
|
+
search(props) {
|
|
405
|
+
const { query, language = 'typescript', detail = 'default', maxResults = 5, maxLength = 100_000 } = props;
|
|
406
|
+
const useMarkdown = detail === 'verbose' || detail === 'high';
|
|
407
|
+
// Search both indices and merge results by score.
|
|
408
|
+
// Filter prose hits so language-tagged content (READMEs and docs with
|
|
409
|
+
// frontmatter) only matches the requested language.
|
|
410
|
+
const methodHits = this.methodIndex
|
|
411
|
+
.search(query)
|
|
412
|
+
.map((hit) => ({ ...hit, _kind: 'http_method' }));
|
|
413
|
+
const proseHits = this.proseIndex
|
|
414
|
+
.search(query)
|
|
415
|
+
.filter((hit) => {
|
|
416
|
+
const source = hit['_original']?.source;
|
|
417
|
+
if (!source)
|
|
418
|
+
return true;
|
|
419
|
+
// Check for language-tagged sources: "readme:<lang>" or "lang:<lang>:<filename>"
|
|
420
|
+
let taggedLang;
|
|
421
|
+
if (source.startsWith('readme:'))
|
|
422
|
+
taggedLang = source.slice('readme:'.length);
|
|
423
|
+
else if (source.startsWith('lang:'))
|
|
424
|
+
taggedLang = source.split(':')[1];
|
|
425
|
+
if (!taggedLang)
|
|
426
|
+
return true;
|
|
427
|
+
return taggedLang === language || (language === 'javascript' && taggedLang === 'typescript');
|
|
428
|
+
})
|
|
429
|
+
.map((hit) => ({ ...hit, _kind: 'prose' }));
|
|
430
|
+
const merged = [...methodHits, ...proseHits].sort((a, b) => b.score - a.score);
|
|
431
|
+
const top = merged.slice(0, maxResults);
|
|
432
|
+
const fullResults = [];
|
|
433
|
+
for (const hit of top) {
|
|
434
|
+
const original = hit['_original'];
|
|
435
|
+
if (hit._kind === 'http_method') {
|
|
436
|
+
const m = original;
|
|
437
|
+
if (useMarkdown && m.markdown) {
|
|
438
|
+
fullResults.push(m.markdown);
|
|
439
|
+
}
|
|
440
|
+
else {
|
|
441
|
+
// Use per-language data when available, falling back to the
|
|
442
|
+
// top-level fields (which are TypeScript-specific in the
|
|
443
|
+
// legacy codepath).
|
|
444
|
+
const langData = m.perLanguage?.[language];
|
|
445
|
+
fullResults.push({
|
|
446
|
+
method: langData?.method ?? m.qualified,
|
|
447
|
+
summary: m.summary,
|
|
448
|
+
description: m.description,
|
|
449
|
+
endpoint: `${m.httpMethod.toUpperCase()} ${m.endpoint}`,
|
|
450
|
+
...(langData?.example ? { example: langData.example } : {}),
|
|
451
|
+
...(m.params ? { params: m.params } : {}),
|
|
452
|
+
...(m.response ? { response: m.response } : {}),
|
|
453
|
+
});
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
else {
|
|
457
|
+
const c = original;
|
|
458
|
+
fullResults.push({
|
|
459
|
+
content: c.content,
|
|
460
|
+
...(c.source ? { source: c.source } : {}),
|
|
461
|
+
});
|
|
462
|
+
}
|
|
463
|
+
}
|
|
464
|
+
let totalLength = 0;
|
|
465
|
+
const results = [];
|
|
466
|
+
for (const result of fullResults) {
|
|
467
|
+
const len = typeof result === 'string' ? result.length : JSON.stringify(result).length;
|
|
468
|
+
totalLength += len;
|
|
469
|
+
if (totalLength > maxLength)
|
|
470
|
+
break;
|
|
471
|
+
results.push(result);
|
|
472
|
+
}
|
|
473
|
+
if (results.length < fullResults.length) {
|
|
474
|
+
results.unshift(`Truncated; showing ${results.length} of ${fullResults.length} results.`);
|
|
475
|
+
}
|
|
476
|
+
return { results };
|
|
477
|
+
}
|
|
478
|
+
indexMethods(methods) {
|
|
479
|
+
const docs = methods.map((m, i) => ({
|
|
480
|
+
id: `method-${i}`,
|
|
481
|
+
kind: 'http_method',
|
|
482
|
+
name: m.name,
|
|
483
|
+
endpoint: m.endpoint,
|
|
484
|
+
summary: m.summary,
|
|
485
|
+
description: m.description,
|
|
486
|
+
qualified: m.qualified,
|
|
487
|
+
stainlessPath: m.stainlessPath,
|
|
488
|
+
_original: m,
|
|
489
|
+
}));
|
|
490
|
+
if (docs.length > 0) {
|
|
491
|
+
this.methodIndex.addAll(docs);
|
|
492
|
+
}
|
|
493
|
+
}
|
|
494
|
+
async loadDocsDirectory(docsDir) {
|
|
495
|
+
let entries;
|
|
496
|
+
try {
|
|
497
|
+
entries = await fs.readdir(docsDir, { withFileTypes: true });
|
|
498
|
+
}
|
|
499
|
+
catch (err) {
|
|
500
|
+
getLogger().warn({ err, docsDir }, 'Could not read docs directory');
|
|
501
|
+
return;
|
|
502
|
+
}
|
|
503
|
+
const files = entries
|
|
504
|
+
.filter((e) => e.isFile())
|
|
505
|
+
.filter((e) => e.name.endsWith('.md') || e.name.endsWith('.markdown') || e.name.endsWith('.json'));
|
|
506
|
+
for (const file of files) {
|
|
507
|
+
try {
|
|
508
|
+
const filePath = path.join(docsDir, file.name);
|
|
509
|
+
const content = await fs.readFile(filePath, 'utf-8');
|
|
510
|
+
if (file.name.endsWith('.json')) {
|
|
511
|
+
const texts = extractTexts(JSON.parse(content));
|
|
512
|
+
if (texts.length > 0) {
|
|
513
|
+
this.indexProse(texts.join('\n\n'), file.name);
|
|
514
|
+
}
|
|
515
|
+
}
|
|
516
|
+
else {
|
|
517
|
+
// Parse optional YAML frontmatter for language tagging.
|
|
518
|
+
// Files with a "language" field in frontmatter will only
|
|
519
|
+
// surface in searches for that language.
|
|
520
|
+
//
|
|
521
|
+
// Example:
|
|
522
|
+
// ---
|
|
523
|
+
// language: python
|
|
524
|
+
// ---
|
|
525
|
+
// # Error handling in Python
|
|
526
|
+
// ...
|
|
527
|
+
const frontmatter = parseFrontmatter(content);
|
|
528
|
+
const source = frontmatter.language ? `lang:${frontmatter.language}:${file.name}` : file.name;
|
|
529
|
+
this.indexProse(content, source);
|
|
530
|
+
}
|
|
531
|
+
}
|
|
532
|
+
catch (err) {
|
|
533
|
+
getLogger().warn({ err, file: file.name }, 'Failed to index docs file');
|
|
534
|
+
}
|
|
535
|
+
}
|
|
536
|
+
}
|
|
537
|
+
indexProse(markdown, source) {
|
|
538
|
+
const chunks = chunkMarkdown(markdown);
|
|
539
|
+
const baseId = this.proseIndex.documentCount;
|
|
540
|
+
const docs = chunks.map((chunk, i) => ({
|
|
541
|
+
id: `prose-${baseId + i}`,
|
|
542
|
+
kind: 'prose',
|
|
543
|
+
content: chunk.content,
|
|
544
|
+
...(chunk.sectionContext != null ? { sectionContext: chunk.sectionContext } : {}),
|
|
545
|
+
_original: { ...chunk, source },
|
|
546
|
+
}));
|
|
547
|
+
if (docs.length > 0) {
|
|
548
|
+
this.proseIndex.addAll(docs);
|
|
549
|
+
}
|
|
550
|
+
}
|
|
551
|
+
}
|
|
552
|
+
/** Lightweight markdown chunker — splits on headers, chunks by word count. */
|
|
553
|
+
function chunkMarkdown(markdown) {
|
|
554
|
+
// Strip YAML frontmatter
|
|
555
|
+
const stripped = markdown.replace(/^---\n[\s\S]*?\n---\n?/, '');
|
|
556
|
+
const lines = stripped.split('\n');
|
|
557
|
+
const chunks = [];
|
|
558
|
+
const headers = [];
|
|
559
|
+
let current = [];
|
|
560
|
+
const flush = () => {
|
|
561
|
+
const text = current.join('\n').trim();
|
|
562
|
+
if (!text)
|
|
563
|
+
return;
|
|
564
|
+
const sectionContext = headers.length > 0 ? headers.join(' > ') : undefined;
|
|
565
|
+
// Split into ~200-word chunks
|
|
566
|
+
const words = text.split(/\s+/);
|
|
567
|
+
for (let i = 0; i < words.length; i += 200) {
|
|
568
|
+
const slice = words.slice(i, i + 200).join(' ');
|
|
569
|
+
if (slice) {
|
|
570
|
+
chunks.push({ content: slice, tag: 'p', ...(sectionContext != null ? { sectionContext } : {}) });
|
|
571
|
+
}
|
|
572
|
+
}
|
|
573
|
+
current = [];
|
|
574
|
+
};
|
|
575
|
+
for (const line of lines) {
|
|
576
|
+
const headerMatch = line.match(/^(#{1,6})\s+(.+)/);
|
|
577
|
+
if (headerMatch) {
|
|
578
|
+
flush();
|
|
579
|
+
const level = headerMatch[1].length;
|
|
580
|
+
const text = headerMatch[2].trim();
|
|
581
|
+
while (headers.length >= level)
|
|
582
|
+
headers.pop();
|
|
583
|
+
headers.push(text);
|
|
584
|
+
}
|
|
585
|
+
else {
|
|
586
|
+
current.push(line);
|
|
587
|
+
}
|
|
588
|
+
}
|
|
589
|
+
flush();
|
|
590
|
+
return chunks;
|
|
591
|
+
}
|
|
592
|
+
/** Recursively extracts string values from a JSON structure. */
|
|
593
|
+
function extractTexts(data, depth = 0) {
|
|
594
|
+
if (depth > 10)
|
|
595
|
+
return [];
|
|
596
|
+
if (typeof data === 'string')
|
|
597
|
+
return data.trim() ? [data] : [];
|
|
598
|
+
if (Array.isArray(data))
|
|
599
|
+
return data.flatMap((item) => extractTexts(item, depth + 1));
|
|
600
|
+
if (typeof data === 'object' && data !== null) {
|
|
601
|
+
return Object.values(data).flatMap((v) => extractTexts(v, depth + 1));
|
|
602
|
+
}
|
|
603
|
+
return [];
|
|
604
|
+
}
|
|
605
|
+
/** Parses YAML frontmatter from a markdown string, extracting the language field if present. */
|
|
606
|
+
function parseFrontmatter(markdown) {
|
|
607
|
+
const match = markdown.match(/^---\n([\s\S]*?)\n---/);
|
|
608
|
+
if (!match)
|
|
609
|
+
return {};
|
|
610
|
+
const body = match[1] ?? '';
|
|
611
|
+
const langMatch = body.match(/^language:\s*(.+)$/m);
|
|
612
|
+
return langMatch ? { language: langMatch[1].trim() } : {};
|
|
613
|
+
}
|
|
614
|
+
//# sourceMappingURL=local-docs-search.mjs.map
|