mcp-scraper 0.31.0 → 0.32.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/README.md +1 -1
- package/dist/bin/api-server.cjs +101 -38
- package/dist/bin/api-server.cjs.map +1 -1
- package/dist/bin/api-server.js +2 -2
- package/dist/bin/mcp-scraper-cli.cjs +4 -1
- package/dist/bin/mcp-scraper-cli.cjs.map +1 -1
- package/dist/bin/mcp-scraper-cli.js +3 -3
- package/dist/bin/mcp-scraper-install.cjs +1 -1
- package/dist/bin/mcp-scraper-install.cjs.map +1 -1
- package/dist/bin/mcp-scraper-install.js +1 -1
- package/dist/bin/mcp-stdio-server.cjs +9 -6
- package/dist/bin/mcp-stdio-server.cjs.map +1 -1
- package/dist/bin/mcp-stdio-server.js +3 -3
- package/dist/bin/paa-harvest.cjs +26 -4
- package/dist/bin/paa-harvest.cjs.map +1 -1
- package/dist/bin/paa-harvest.js +2 -2
- package/dist/{chunk-ZOXL3VWO.js → chunk-2FY4VBAY.js} +8 -8
- package/dist/chunk-2FY4VBAY.js.map +1 -0
- package/dist/{chunk-KAMKTSJQ.js → chunk-55M5CE5L.js} +2 -2
- package/dist/{chunk-ZQSHKWV4.js → chunk-PTHY7NYD.js} +4 -1
- package/dist/chunk-PTHY7NYD.js.map +1 -0
- package/dist/{chunk-YH5DRFWQ.js → chunk-RDCCU7CQ.js} +25 -6
- package/dist/chunk-RDCCU7CQ.js.map +1 -0
- package/dist/chunk-VJBS6RPB.js +7 -0
- package/dist/chunk-VJBS6RPB.js.map +1 -0
- package/dist/index.cjs +26 -4
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +9 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.js +2 -2
- package/dist/{server-DS3ZSNNO.js → server-GXTYKIAX.js} +77 -35
- package/dist/{server-DS3ZSNNO.js.map → server-GXTYKIAX.js.map} +1 -1
- package/dist/{worker-RYP5EOV5.js → worker-7DJYUACV.js} +3 -3
- package/docs/mcp-tool-manifest.generated.json +7 -7
- package/package.json +1 -1
- package/dist/chunk-W3GYPHFL.js +0 -7
- package/dist/chunk-W3GYPHFL.js.map +0 -1
- package/dist/chunk-YH5DRFWQ.js.map +0 -1
- package/dist/chunk-ZOXL3VWO.js.map +0 -1
- package/dist/chunk-ZQSHKWV4.js.map +0 -1
- /package/dist/{chunk-KAMKTSJQ.js.map → chunk-55M5CE5L.js.map} +0 -0
- /package/dist/{worker-RYP5EOV5.js.map → worker-7DJYUACV.js.map} +0 -0
package/dist/index.d.cts
CHANGED
|
@@ -8,6 +8,9 @@ declare const HarvestOptionsSchema: z.ZodObject<{
|
|
|
8
8
|
device: z.ZodDefault<z.ZodEnum<["desktop", "mobile"]>>;
|
|
9
9
|
proxyMode: z.ZodDefault<z.ZodEnum<["location", "configured", "none"]>>;
|
|
10
10
|
proxyZip: z.ZodOptional<z.ZodString>;
|
|
11
|
+
keepDefaultProxy: z.ZodOptional<z.ZodBoolean>;
|
|
12
|
+
requireUsEgress: z.ZodOptional<z.ZodBoolean>;
|
|
13
|
+
maxAttempts: z.ZodOptional<z.ZodNumber>;
|
|
11
14
|
debug: z.ZodDefault<z.ZodBoolean>;
|
|
12
15
|
depth: z.ZodDefault<z.ZodNumber>;
|
|
13
16
|
maxQuestions: z.ZodDefault<z.ZodNumber>;
|
|
@@ -38,6 +41,9 @@ declare const HarvestOptionsSchema: z.ZodObject<{
|
|
|
38
41
|
pages: number;
|
|
39
42
|
location?: string | undefined;
|
|
40
43
|
proxyZip?: string | undefined;
|
|
44
|
+
keepDefaultProxy?: boolean | undefined;
|
|
45
|
+
requireUsEgress?: boolean | undefined;
|
|
46
|
+
maxAttempts?: number | undefined;
|
|
41
47
|
profileDir?: string | undefined;
|
|
42
48
|
proxy?: string | undefined;
|
|
43
49
|
kernelApiKey?: string | undefined;
|
|
@@ -52,6 +58,9 @@ declare const HarvestOptionsSchema: z.ZodObject<{
|
|
|
52
58
|
device?: "desktop" | "mobile" | undefined;
|
|
53
59
|
proxyMode?: "none" | "location" | "configured" | undefined;
|
|
54
60
|
proxyZip?: string | undefined;
|
|
61
|
+
keepDefaultProxy?: boolean | undefined;
|
|
62
|
+
requireUsEgress?: boolean | undefined;
|
|
63
|
+
maxAttempts?: number | undefined;
|
|
55
64
|
debug?: boolean | undefined;
|
|
56
65
|
depth?: number | undefined;
|
|
57
66
|
maxQuestions?: number | undefined;
|
package/dist/index.d.ts
CHANGED
|
@@ -8,6 +8,9 @@ declare const HarvestOptionsSchema: z.ZodObject<{
|
|
|
8
8
|
device: z.ZodDefault<z.ZodEnum<["desktop", "mobile"]>>;
|
|
9
9
|
proxyMode: z.ZodDefault<z.ZodEnum<["location", "configured", "none"]>>;
|
|
10
10
|
proxyZip: z.ZodOptional<z.ZodString>;
|
|
11
|
+
keepDefaultProxy: z.ZodOptional<z.ZodBoolean>;
|
|
12
|
+
requireUsEgress: z.ZodOptional<z.ZodBoolean>;
|
|
13
|
+
maxAttempts: z.ZodOptional<z.ZodNumber>;
|
|
11
14
|
debug: z.ZodDefault<z.ZodBoolean>;
|
|
12
15
|
depth: z.ZodDefault<z.ZodNumber>;
|
|
13
16
|
maxQuestions: z.ZodDefault<z.ZodNumber>;
|
|
@@ -38,6 +41,9 @@ declare const HarvestOptionsSchema: z.ZodObject<{
|
|
|
38
41
|
pages: number;
|
|
39
42
|
location?: string | undefined;
|
|
40
43
|
proxyZip?: string | undefined;
|
|
44
|
+
keepDefaultProxy?: boolean | undefined;
|
|
45
|
+
requireUsEgress?: boolean | undefined;
|
|
46
|
+
maxAttempts?: number | undefined;
|
|
41
47
|
profileDir?: string | undefined;
|
|
42
48
|
proxy?: string | undefined;
|
|
43
49
|
kernelApiKey?: string | undefined;
|
|
@@ -52,6 +58,9 @@ declare const HarvestOptionsSchema: z.ZodObject<{
|
|
|
52
58
|
device?: "desktop" | "mobile" | undefined;
|
|
53
59
|
proxyMode?: "none" | "location" | "configured" | undefined;
|
|
54
60
|
proxyZip?: string | undefined;
|
|
61
|
+
keepDefaultProxy?: boolean | undefined;
|
|
62
|
+
requireUsEgress?: boolean | undefined;
|
|
63
|
+
maxAttempts?: number | undefined;
|
|
55
64
|
debug?: boolean | undefined;
|
|
56
65
|
depth?: number | undefined;
|
|
57
66
|
maxQuestions?: number | undefined;
|
package/dist/index.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import {
|
|
2
2
|
harvest
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-RDCCU7CQ.js";
|
|
4
4
|
import {
|
|
5
5
|
recordVendorUsage
|
|
6
6
|
} from "./chunk-MTSBI7ZH.js";
|
|
7
7
|
import "./chunk-K443GQY5.js";
|
|
8
|
-
import "./chunk-
|
|
8
|
+
import "./chunk-PTHY7NYD.js";
|
|
9
9
|
import "./chunk-M2S27J6Z.js";
|
|
10
10
|
import "./chunk-ICT7DDHL.js";
|
|
11
11
|
|
|
@@ -16,7 +16,7 @@ import {
|
|
|
16
16
|
harvest,
|
|
17
17
|
normalizeLocation,
|
|
18
18
|
resolveKernelProxyId
|
|
19
|
-
} from "./chunk-
|
|
19
|
+
} from "./chunk-RDCCU7CQ.js";
|
|
20
20
|
import {
|
|
21
21
|
HttpMcpToolExecutor,
|
|
22
22
|
assessTranscriptSignal,
|
|
@@ -36,7 +36,7 @@ import {
|
|
|
36
36
|
sanitizeAttempts,
|
|
37
37
|
sanitizeHarvestResult,
|
|
38
38
|
transcribeMediaUrl
|
|
39
|
-
} from "./chunk-
|
|
39
|
+
} from "./chunk-2FY4VBAY.js";
|
|
40
40
|
import {
|
|
41
41
|
auditImages,
|
|
42
42
|
buildLinkReport,
|
|
@@ -65,7 +65,7 @@ import {
|
|
|
65
65
|
workflowOutputBaseDir,
|
|
66
66
|
workflowStepCount,
|
|
67
67
|
workflowSupportsSteps
|
|
68
|
-
} from "./chunk-
|
|
68
|
+
} from "./chunk-55M5CE5L.js";
|
|
69
69
|
import "./chunk-K443GQY5.js";
|
|
70
70
|
import {
|
|
71
71
|
DEFAULT_MAPS_PROXY_MODE,
|
|
@@ -76,8 +76,8 @@ import {
|
|
|
76
76
|
RawMapsHoursRowSchema,
|
|
77
77
|
RawMapsOverviewSchema,
|
|
78
78
|
RawMapsReviewStatsSchema
|
|
79
|
-
} from "./chunk-
|
|
80
|
-
import "./chunk-
|
|
79
|
+
} from "./chunk-PTHY7NYD.js";
|
|
80
|
+
import "./chunk-VJBS6RPB.js";
|
|
81
81
|
import {
|
|
82
82
|
completeExtractJob,
|
|
83
83
|
countSuccessfulPages,
|
|
@@ -129,6 +129,7 @@ import {
|
|
|
129
129
|
} from "./chunk-4767BA2O.js";
|
|
130
130
|
import {
|
|
131
131
|
CaptchaError,
|
|
132
|
+
ExtractionError,
|
|
132
133
|
RECAPTCHA_INSTRUCTIONS,
|
|
133
134
|
sanitizeVendorName
|
|
134
135
|
} from "./chunk-M2S27J6Z.js";
|
|
@@ -13088,6 +13089,12 @@ function buildGoogleLocalResultsUrl(input) {
|
|
|
13088
13089
|
if (input.location) params.set("uule", encodeUule(normalizeLocation(input.location)));
|
|
13089
13090
|
return `https://www.google.com/search?${params.toString()}`;
|
|
13090
13091
|
}
|
|
13092
|
+
function buildGoogleOrganicSearchUrl(input) {
|
|
13093
|
+
const query = [input.query, input.location].filter(Boolean).join(" ");
|
|
13094
|
+
const params = new URLSearchParams({ q: query, gl: input.gl, hl: input.hl, pws: "0" });
|
|
13095
|
+
if (input.location) params.set("uule", encodeUule(normalizeLocation(input.location)));
|
|
13096
|
+
return `https://www.google.com/search?${params.toString()}`;
|
|
13097
|
+
}
|
|
13091
13098
|
var MapsSearchExtractor = class {
|
|
13092
13099
|
constructor(driver) {
|
|
13093
13100
|
this.driver = driver;
|
|
@@ -13096,13 +13103,14 @@ var MapsSearchExtractor = class {
|
|
|
13096
13103
|
async extract(options) {
|
|
13097
13104
|
const startMs = Date.now();
|
|
13098
13105
|
const searchQuery = [options.query, options.location].filter(Boolean).join(" ");
|
|
13099
|
-
const searchUrl =
|
|
13106
|
+
const searchUrl = buildGoogleOrganicSearchUrl(options);
|
|
13100
13107
|
const config = {
|
|
13101
13108
|
headless: options.headless,
|
|
13102
13109
|
kernelApiKey: options.kernelApiKey,
|
|
13103
13110
|
kernelProxyId: options.kernelProxyId,
|
|
13104
13111
|
kernelProxyResolution: options.kernelProxyResolution,
|
|
13105
13112
|
proxyMode: options.proxyMode,
|
|
13113
|
+
keepDefaultProxy: options.proxyMode !== "location" && options.proxyMode !== "configured" && !options.kernelProxyId,
|
|
13106
13114
|
viewport: { width: 1280, height: 900 },
|
|
13107
13115
|
locale: `${options.hl}-${options.gl.toUpperCase()}`,
|
|
13108
13116
|
debug: options.debug
|
|
@@ -13113,6 +13121,10 @@ var MapsSearchExtractor = class {
|
|
|
13113
13121
|
await page.goto(searchUrl, { waitUntil: "domcontentloaded", timeout: 6e4 });
|
|
13114
13122
|
await page.waitForTimeout(LOCAL_RESULTS_WAIT_MS);
|
|
13115
13123
|
if (await this.detectBlock(page)) throw new CaptchaError(RECAPTCHA_INSTRUCTIONS);
|
|
13124
|
+
const reachedFinder = await this.clickIntoLocalFinder(page);
|
|
13125
|
+
if (!reachedFinder) throw new ExtractionError('Google "More businesses" control was not found on the organic results page');
|
|
13126
|
+
await page.waitForTimeout(LOCAL_RESULTS_WAIT_MS);
|
|
13127
|
+
if (await this.detectBlock(page)) throw new CaptchaError(RECAPTCHA_INSTRUCTIONS);
|
|
13116
13128
|
const results = await this.collectResults(page, options);
|
|
13117
13129
|
return {
|
|
13118
13130
|
query: options.query,
|
|
@@ -13129,6 +13141,17 @@ var MapsSearchExtractor = class {
|
|
|
13129
13141
|
await this.driver.close();
|
|
13130
13142
|
}
|
|
13131
13143
|
}
|
|
13144
|
+
async clickIntoLocalFinder(page) {
|
|
13145
|
+
const control = page.getByRole("link", { name: /more (businesses|places|results)/i }).or(page.getByRole("button", { name: /more (businesses|places|results)/i })).first();
|
|
13146
|
+
const visible = await control.isVisible({ timeout: 1e4 }).catch(() => false);
|
|
13147
|
+
if (!visible) return false;
|
|
13148
|
+
await control.click({ timeout: 1e4 }).catch(() => {
|
|
13149
|
+
});
|
|
13150
|
+
await page.waitForTimeout(5e3);
|
|
13151
|
+
return page.evaluate(
|
|
13152
|
+
() => /[?&]udm=1/.test(location.href) || document.querySelectorAll('a[href*="/maps/place/"]').length > 0
|
|
13153
|
+
);
|
|
13154
|
+
}
|
|
13132
13155
|
async detectBlock(page) {
|
|
13133
13156
|
return page.evaluate(() => {
|
|
13134
13157
|
const text2 = document.body.innerText.slice(0, 2e3);
|
|
@@ -13182,29 +13205,38 @@ var MapsSearchExtractor = class {
|
|
|
13182
13205
|
};
|
|
13183
13206
|
const phonePattern = /(?:\+?1[\s.-]?)?\(?\d{3}\)?[\s.-]\d{3}[\s.-]\d{4}/;
|
|
13184
13207
|
const addressPattern = /\b[A-Z]{2}\s+\d{5}(?:-\d{4})?\b|\b(?:St|Street|Ave|Avenue|Rd|Road|Blvd|Boulevard|Dr|Drive|Ln|Lane|Way|Pkwy|Parkway)\b/i;
|
|
13185
|
-
const
|
|
13186
|
-
const
|
|
13187
|
-
return Boolean(
|
|
13208
|
+
const headings = Array.from(document.querySelectorAll('div[role="heading"]')).filter((heading) => {
|
|
13209
|
+
const text2 = normalize(heading.textContent);
|
|
13210
|
+
return Boolean(text2) && !/^(?:businesses|places|sponsored|people also ask|discussions and forums|more businesses|more places|custom date range|choose what you)/i.test(text2 ?? "");
|
|
13188
13211
|
});
|
|
13189
13212
|
const seen = /* @__PURE__ */ new Set();
|
|
13190
13213
|
const out = [];
|
|
13191
|
-
|
|
13192
|
-
|
|
13214
|
+
let cardIndex = -1;
|
|
13215
|
+
for (const heading of headings) {
|
|
13216
|
+
let card = heading;
|
|
13217
|
+
for (let hop = 0; hop < 8; hop++) {
|
|
13218
|
+
const parent = card.parentElement;
|
|
13219
|
+
if (!parent || parent.querySelectorAll('div[role="heading"]').length > 1) break;
|
|
13220
|
+
card = parent;
|
|
13221
|
+
}
|
|
13222
|
+
if (card.closest('[role="dialog"], dialog')) continue;
|
|
13223
|
+
const name = normalize(heading.textContent);
|
|
13193
13224
|
if (!name) continue;
|
|
13194
|
-
const
|
|
13195
|
-
|
|
13225
|
+
const lines = (card.innerText ?? "").split("\n").map((line) => normalize(line)).filter((line) => Boolean(line));
|
|
13226
|
+
if (/^sponsored$/i.test(lines[0] ?? "")) continue;
|
|
13227
|
+
const ratingLine = lines.find((line) => /\d(?:\.\d)?\s*\(/.test(line)) ?? "";
|
|
13228
|
+
const rating = ratingLine.match(/(\d(?:\.\d)?)\s*\(/)?.[1] ?? null;
|
|
13229
|
+
const reviewCount = ratingLine.match(/\((\d[\d,]*)\)/)?.[1]?.replace(/,/g, "") ?? null;
|
|
13230
|
+
const category = normalize(ratingLine.split("\xB7").slice(1).join("\xB7"));
|
|
13231
|
+
const phone = lines.map((line) => line.match(phonePattern)?.[0]).find((value) => Boolean(value)) ?? null;
|
|
13232
|
+
const hoursStatus = normalize((lines.find((line) => /\b(?:open|closed|opens|closes)\b/i.test(line)) ?? "").split("\xB7")[0] ?? "");
|
|
13233
|
+
const address = lines.find((line) => addressPattern.test(line)) ?? null;
|
|
13234
|
+
const websiteUrl = Array.from(card.querySelectorAll("a[href]")).map((anchor) => anchor.href).find((href) => /^https?:/i.test(href) && !/google\.|gstatic|googleusercontent/.test(href)) ?? null;
|
|
13235
|
+
if (!rating && !(phone && websiteUrl)) continue;
|
|
13236
|
+
const key = `${name.toLowerCase()}|${lines.join(" ").toLowerCase()}`;
|
|
13196
13237
|
if (seen.has(key)) continue;
|
|
13197
13238
|
seen.add(key);
|
|
13198
|
-
|
|
13199
|
-
const aria = normalize(card.getAttribute("aria-label"));
|
|
13200
|
-
const rating = (aria ?? text2).match(/(?:rated\s+)?(\d(?:\.\d)?)\s*(?:out of 5)?/i)?.[1] ?? null;
|
|
13201
|
-
const reviewCount = (aria ?? text2).match(/(?:\(|·\s*)([\d,]+)\s+(?:user\s+)?reviews?\b/i)?.[1]?.replace(/,/g, "") ?? null;
|
|
13202
|
-
const phone = lines.find((line) => phonePattern.test(line)) ?? null;
|
|
13203
|
-
const address = lines.find((line) => addressPattern.test(line)) ?? null;
|
|
13204
|
-
const hoursStatus = lines.find((line) => /\b(?:open|closed|opens|closes)\b/i.test(line)) ?? null;
|
|
13205
|
-
const category = lines.find(
|
|
13206
|
-
(line) => line !== name && line !== phone && line !== address && line !== hoursStatus && !/^(?:rated|\d[\d.,]*\s*(?:out of 5|reviews?)?)\b/i.test(line) && !/sponsored|website|directions|call|save|share|more/i.test(line)
|
|
13207
|
-
) ?? null;
|
|
13239
|
+
cardIndex += 1;
|
|
13208
13240
|
const mapsSearchUrl = `https://www.google.com/maps/search/${encodeURIComponent([name, locationHint].filter(Boolean).join(" "))}`;
|
|
13209
13241
|
out.push({
|
|
13210
13242
|
cardIndex,
|
|
@@ -13219,7 +13251,7 @@ var MapsSearchExtractor = class {
|
|
|
13219
13251
|
address,
|
|
13220
13252
|
phone,
|
|
13221
13253
|
hoursStatus,
|
|
13222
|
-
websiteUrl
|
|
13254
|
+
websiteUrl,
|
|
13223
13255
|
directionsUrl: `https://www.google.com/maps/dir/?api=1&destination=${encodeURIComponent([name, address].filter(Boolean).join(", "))}`,
|
|
13224
13256
|
metadata: lines.slice(0, 20)
|
|
13225
13257
|
});
|
|
@@ -13228,17 +13260,27 @@ var MapsSearchExtractor = class {
|
|
|
13228
13260
|
}, fallbackLocation);
|
|
13229
13261
|
}
|
|
13230
13262
|
async openCardAndExtractDialog(page, card, includeServices) {
|
|
13263
|
+
if (!includeServices) return null;
|
|
13231
13264
|
const clicked = await page.evaluate((input) => {
|
|
13232
13265
|
const normalize = (value) => (value ?? "").replace(/\s+/g, " ").trim().toLowerCase();
|
|
13233
|
-
const
|
|
13234
|
-
|
|
13235
|
-
|
|
13236
|
-
|
|
13237
|
-
|
|
13238
|
-
|
|
13239
|
-
|
|
13240
|
-
|
|
13241
|
-
|
|
13266
|
+
const headings = Array.from(document.querySelectorAll('div[role="heading"]'));
|
|
13267
|
+
for (const heading of headings) {
|
|
13268
|
+
let target = heading;
|
|
13269
|
+
for (let hop = 0; hop < 8; hop++) {
|
|
13270
|
+
const parent = target.parentElement;
|
|
13271
|
+
if (!parent || parent.querySelectorAll('div[role="heading"]').length > 1) break;
|
|
13272
|
+
target = parent;
|
|
13273
|
+
}
|
|
13274
|
+
if (target.closest('[role="dialog"], dialog')) continue;
|
|
13275
|
+
const name = normalize(heading.textContent);
|
|
13276
|
+
if (!name) continue;
|
|
13277
|
+
const lines = (target.innerText ?? "").split("\n").map((line) => normalize(line)).filter(Boolean);
|
|
13278
|
+
if (`${name}|${lines.join(" ")}` !== input.cardKey) continue;
|
|
13279
|
+
target.click();
|
|
13280
|
+
return true;
|
|
13281
|
+
}
|
|
13282
|
+
return false;
|
|
13283
|
+
}, { cardKey: card.cardKey });
|
|
13242
13284
|
if (!clicked) return null;
|
|
13243
13285
|
const dialog = page.locator('dialog, [role="dialog"]').filter({ has: page.locator('h1, h2, [role="heading"]') }).last();
|
|
13244
13286
|
await dialog.waitFor({ state: "visible", timeout: 6e3 }).catch(() => {
|
|
@@ -27382,7 +27424,7 @@ app.get("/cron/tick", async (c) => {
|
|
|
27382
27424
|
if (!process.env.CRON_SECRET || secret2 !== `Bearer ${process.env.CRON_SECRET}`) {
|
|
27383
27425
|
return c.json({ error: "Unauthorized" }, 401);
|
|
27384
27426
|
}
|
|
27385
|
-
const { drainQueue } = await import("./worker-
|
|
27427
|
+
const { drainQueue } = await import("./worker-7DJYUACV.js");
|
|
27386
27428
|
const budget = { maxJobs: 10, deadlineMs: Date.now() + 28e4 };
|
|
27387
27429
|
const workflowDispatchResult = await dispatchDueWorkflowSchedules(`${new URL(c.req.url).protocol}//${new URL(c.req.url).host}`);
|
|
27388
27430
|
const [results, sweepResult, reapResult, expiredResult, blobCleanup, connectedDataArtifactCleanup] = await Promise.all([
|
|
@@ -27585,4 +27627,4 @@ app.get("/blog/:slug/", (c) => {
|
|
|
27585
27627
|
export {
|
|
27586
27628
|
app
|
|
27587
27629
|
};
|
|
27588
|
-
//# sourceMappingURL=server-
|
|
27630
|
+
//# sourceMappingURL=server-GXTYKIAX.js.map
|