@arabold/docs-mcp-server 1.30.0 → 1.31.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/dist/assets/main.css +1 -1
- package/dist/index.js +588 -222
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/public/assets/main.css +1 -1
package/dist/index.js
CHANGED
|
@@ -1579,7 +1579,7 @@ function createMcpServerInstance(tools, readOnly = false) {
|
|
|
1579
1579
|
"Re-scrape a previously indexed library version, updating only changed pages.",
|
|
1580
1580
|
{
|
|
1581
1581
|
library: z.string().trim().describe("Library name."),
|
|
1582
|
-
version: z.string().trim().optional().describe("Library version (optional, refreshes
|
|
1582
|
+
version: z.string().trim().optional().describe("Library version (optional, refreshes latest if omitted).")
|
|
1583
1583
|
},
|
|
1584
1584
|
{
|
|
1585
1585
|
title: "Refresh Library Version",
|
|
@@ -1833,7 +1833,7 @@ ${formattedJob}`);
|
|
|
1833
1833
|
"Remove indexed documentation for a library version. Use only if explicitly instructed.",
|
|
1834
1834
|
{
|
|
1835
1835
|
library: z.string().trim().describe("Library name."),
|
|
1836
|
-
version: z.string().trim().optional().describe("Library version (optional, removes
|
|
1836
|
+
version: z.string().trim().optional().describe("Library version (optional, removes latest if omitted).")
|
|
1837
1837
|
},
|
|
1838
1838
|
{
|
|
1839
1839
|
title: "Remove Library Documentation",
|
|
@@ -5269,11 +5269,28 @@ class HtmlPlaywrightMiddleware {
|
|
|
5269
5269
|
logger.debug(`Could not access content frame for iframe ${index + 1}`);
|
|
5270
5270
|
return;
|
|
5271
5271
|
}
|
|
5272
|
-
|
|
5273
|
-
|
|
5274
|
-
}
|
|
5275
|
-
|
|
5276
|
-
|
|
5272
|
+
try {
|
|
5273
|
+
await frame.waitForSelector("body", { timeout: DEFAULT_PAGE_TIMEOUT });
|
|
5274
|
+
} catch {
|
|
5275
|
+
logger.debug(
|
|
5276
|
+
`Timeout waiting for body in iframe ${index + 1} - skipping content extraction`
|
|
5277
|
+
);
|
|
5278
|
+
return;
|
|
5279
|
+
}
|
|
5280
|
+
try {
|
|
5281
|
+
await this.waitForLoadingToComplete(frame);
|
|
5282
|
+
} catch {
|
|
5283
|
+
logger.debug(
|
|
5284
|
+
`Timeout waiting for loading indicators in iframe ${index + 1} - proceeding anyway`
|
|
5285
|
+
);
|
|
5286
|
+
}
|
|
5287
|
+
let content = null;
|
|
5288
|
+
try {
|
|
5289
|
+
content = await this.extractIframeContent(frame);
|
|
5290
|
+
} catch (error) {
|
|
5291
|
+
logger.debug(`Error extracting content from iframe ${index + 1}: ${error}`);
|
|
5292
|
+
return;
|
|
5293
|
+
}
|
|
5277
5294
|
if (content && content.trim().length > 0) {
|
|
5278
5295
|
await this.replaceIframeWithContent(page, index, content);
|
|
5279
5296
|
logger.debug(
|
|
@@ -5284,7 +5301,7 @@ class HtmlPlaywrightMiddleware {
|
|
|
5284
5301
|
}
|
|
5285
5302
|
logger.debug(`Successfully loaded iframe ${index + 1}: ${src}`);
|
|
5286
5303
|
} catch (error) {
|
|
5287
|
-
logger.debug(`Error
|
|
5304
|
+
logger.debug(`Error processing iframe ${index + 1}: ${error}`);
|
|
5288
5305
|
}
|
|
5289
5306
|
}
|
|
5290
5307
|
/**
|
|
@@ -5447,23 +5464,31 @@ class HtmlPlaywrightMiddleware {
|
|
|
5447
5464
|
origin,
|
|
5448
5465
|
reqOrigin ?? void 0
|
|
5449
5466
|
);
|
|
5450
|
-
|
|
5451
|
-
|
|
5452
|
-
|
|
5453
|
-
|
|
5454
|
-
|
|
5455
|
-
|
|
5456
|
-
|
|
5457
|
-
|
|
5458
|
-
|
|
5459
|
-
|
|
5460
|
-
|
|
5461
|
-
|
|
5462
|
-
|
|
5463
|
-
|
|
5467
|
+
try {
|
|
5468
|
+
const response = await route.fetch({ headers: headers2 });
|
|
5469
|
+
const body = await response.text();
|
|
5470
|
+
if (response.status() >= 200 && response.status() < 300 && body.length > 0) {
|
|
5471
|
+
const contentSizeBytes = Buffer.byteLength(body, "utf8");
|
|
5472
|
+
if (contentSizeBytes <= FETCHER_MAX_CACHE_ITEM_SIZE_BYTES) {
|
|
5473
|
+
const contentType = response.headers()["content-type"] || "application/octet-stream";
|
|
5474
|
+
HtmlPlaywrightMiddleware.resourceCache.set(reqUrl, { body, contentType });
|
|
5475
|
+
logger.debug(
|
|
5476
|
+
`Cached ${resourceType}: ${reqUrl} (${contentSizeBytes} bytes, cache size: ${HtmlPlaywrightMiddleware.resourceCache.size})`
|
|
5477
|
+
);
|
|
5478
|
+
} else {
|
|
5479
|
+
logger.debug(
|
|
5480
|
+
`Resource too large to cache: ${reqUrl} (${contentSizeBytes} bytes > ${FETCHER_MAX_CACHE_ITEM_SIZE_BYTES} bytes limit)`
|
|
5481
|
+
);
|
|
5482
|
+
}
|
|
5464
5483
|
}
|
|
5484
|
+
return route.fulfill({ response });
|
|
5485
|
+
} catch (error) {
|
|
5486
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
5487
|
+
logger.debug(
|
|
5488
|
+
`Network error fetching ${resourceType} ${reqUrl}: ${errorMessage}`
|
|
5489
|
+
);
|
|
5490
|
+
return route.abort("failed");
|
|
5465
5491
|
}
|
|
5466
|
-
return route.fulfill({ response });
|
|
5467
5492
|
}
|
|
5468
5493
|
const headers = mergePlaywrightHeaders(
|
|
5469
5494
|
route.request().headers(),
|
|
@@ -5472,7 +5497,13 @@ class HtmlPlaywrightMiddleware {
|
|
|
5472
5497
|
origin,
|
|
5473
5498
|
reqOrigin ?? void 0
|
|
5474
5499
|
);
|
|
5475
|
-
|
|
5500
|
+
try {
|
|
5501
|
+
return await route.continue({ headers });
|
|
5502
|
+
} catch (error) {
|
|
5503
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
5504
|
+
logger.debug(`Network error for ${resourceType} ${reqUrl}: ${errorMessage}`);
|
|
5505
|
+
return route.abort("failed");
|
|
5506
|
+
}
|
|
5476
5507
|
});
|
|
5477
5508
|
}
|
|
5478
5509
|
/**
|
|
@@ -5656,23 +5687,31 @@ ${frame.content}
|
|
|
5656
5687
|
origin ?? void 0,
|
|
5657
5688
|
reqOrigin ?? void 0
|
|
5658
5689
|
);
|
|
5659
|
-
|
|
5660
|
-
|
|
5661
|
-
|
|
5662
|
-
|
|
5663
|
-
|
|
5664
|
-
|
|
5665
|
-
|
|
5666
|
-
|
|
5667
|
-
|
|
5668
|
-
|
|
5669
|
-
|
|
5670
|
-
|
|
5671
|
-
|
|
5672
|
-
|
|
5690
|
+
try {
|
|
5691
|
+
const response = await route.fetch({ headers: headers2 });
|
|
5692
|
+
const body = await response.text();
|
|
5693
|
+
if (response.status() >= 200 && response.status() < 300 && body.length > 0) {
|
|
5694
|
+
const contentSizeBytes = Buffer.byteLength(body, "utf8");
|
|
5695
|
+
if (contentSizeBytes <= FETCHER_MAX_CACHE_ITEM_SIZE_BYTES) {
|
|
5696
|
+
const contentType2 = response.headers()["content-type"] || "application/octet-stream";
|
|
5697
|
+
HtmlPlaywrightMiddleware.resourceCache.set(reqUrl, { body, contentType: contentType2 });
|
|
5698
|
+
logger.debug(
|
|
5699
|
+
`Cached ${resourceType}: ${reqUrl} (${contentSizeBytes} bytes, cache size: ${HtmlPlaywrightMiddleware.resourceCache.size})`
|
|
5700
|
+
);
|
|
5701
|
+
} else {
|
|
5702
|
+
logger.debug(
|
|
5703
|
+
`Resource too large to cache: ${reqUrl} (${contentSizeBytes} bytes > ${FETCHER_MAX_CACHE_ITEM_SIZE_BYTES} bytes limit)`
|
|
5704
|
+
);
|
|
5705
|
+
}
|
|
5673
5706
|
}
|
|
5707
|
+
return route.fulfill({ response });
|
|
5708
|
+
} catch (error) {
|
|
5709
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
5710
|
+
logger.debug(
|
|
5711
|
+
`Network error fetching ${resourceType} ${reqUrl}: ${errorMessage}`
|
|
5712
|
+
);
|
|
5713
|
+
return route.abort("failed");
|
|
5674
5714
|
}
|
|
5675
|
-
return route.fulfill({ response });
|
|
5676
5715
|
}
|
|
5677
5716
|
const headers = mergePlaywrightHeaders(
|
|
5678
5717
|
route.request().headers(),
|
|
@@ -5681,7 +5720,13 @@ ${frame.content}
|
|
|
5681
5720
|
origin ?? void 0,
|
|
5682
5721
|
reqOrigin ?? void 0
|
|
5683
5722
|
);
|
|
5684
|
-
|
|
5723
|
+
try {
|
|
5724
|
+
return await route.continue({ headers });
|
|
5725
|
+
} catch (error) {
|
|
5726
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
5727
|
+
logger.debug(`Network error for ${resourceType} ${reqUrl}: ${errorMessage}`);
|
|
5728
|
+
return route.abort("failed");
|
|
5729
|
+
}
|
|
5685
5730
|
});
|
|
5686
5731
|
await page.goto(context.source, { waitUntil: "load" });
|
|
5687
5732
|
await page.waitForSelector("body, frameset", { timeout: DEFAULT_PAGE_TIMEOUT });
|
|
@@ -7180,6 +7225,24 @@ let PipelineFactory$1 = class PipelineFactory {
|
|
|
7180
7225
|
];
|
|
7181
7226
|
}
|
|
7182
7227
|
};
|
|
7228
|
+
function compareVersionsDescending(a, b) {
|
|
7229
|
+
const aIsUnversioned = a === "" || a === null || a === void 0;
|
|
7230
|
+
const bIsUnversioned = b === "" || b === null || b === void 0;
|
|
7231
|
+
if (aIsUnversioned && bIsUnversioned) return 0;
|
|
7232
|
+
if (aIsUnversioned) return -1;
|
|
7233
|
+
if (bIsUnversioned) return 1;
|
|
7234
|
+
const aSemver = semver__default.valid(a) ?? semver__default.valid(semver__default.coerce(a));
|
|
7235
|
+
const bSemver = semver__default.valid(b) ?? semver__default.valid(semver__default.coerce(b));
|
|
7236
|
+
if (aSemver && bSemver) {
|
|
7237
|
+
return semver__default.rcompare(aSemver, bSemver);
|
|
7238
|
+
}
|
|
7239
|
+
const aLower = a.toLowerCase();
|
|
7240
|
+
const bLower = b.toLowerCase();
|
|
7241
|
+
return bLower.localeCompare(aLower);
|
|
7242
|
+
}
|
|
7243
|
+
function sortVersionsDescending(versions) {
|
|
7244
|
+
return [...versions].sort(compareVersionsDescending);
|
|
7245
|
+
}
|
|
7183
7246
|
class HierarchicalAssemblyStrategy {
|
|
7184
7247
|
/**
|
|
7185
7248
|
* Determines if this strategy can handle the given content type.
|
|
@@ -8887,22 +8950,7 @@ class DocumentStore {
|
|
|
8887
8950
|
});
|
|
8888
8951
|
}
|
|
8889
8952
|
for (const versions of libraryMap.values()) {
|
|
8890
|
-
versions.sort((a, b) =>
|
|
8891
|
-
if (a.version === "" && b.version !== "") {
|
|
8892
|
-
return -1;
|
|
8893
|
-
}
|
|
8894
|
-
if (a.version !== "" && b.version === "") {
|
|
8895
|
-
return 1;
|
|
8896
|
-
}
|
|
8897
|
-
if (a.version === "" && b.version === "") {
|
|
8898
|
-
return 0;
|
|
8899
|
-
}
|
|
8900
|
-
try {
|
|
8901
|
-
return semver__default.compare(a.version, b.version);
|
|
8902
|
-
} catch (_error) {
|
|
8903
|
-
return a.version.localeCompare(b.version);
|
|
8904
|
-
}
|
|
8905
|
-
});
|
|
8953
|
+
versions.sort((a, b) => compareVersionsDescending(a.version, b.version));
|
|
8906
8954
|
}
|
|
8907
8955
|
return libraryMap;
|
|
8908
8956
|
} catch (error) {
|
|
@@ -9680,10 +9728,12 @@ class DocumentManagementService {
|
|
|
9680
9728
|
}
|
|
9681
9729
|
/**
|
|
9682
9730
|
* Returns a list of all available semantic versions for a library.
|
|
9731
|
+
* Sorted in descending order (latest first).
|
|
9683
9732
|
*/
|
|
9684
9733
|
async listVersions(library) {
|
|
9685
9734
|
const versions = await this.store.queryUniqueVersions(library);
|
|
9686
|
-
|
|
9735
|
+
const validVersions = versions.filter((v) => semver__default.valid(v));
|
|
9736
|
+
return sortVersionsDescending(validVersions);
|
|
9687
9737
|
}
|
|
9688
9738
|
/**
|
|
9689
9739
|
* Checks if documents exist for a given library and optional version.
|
|
@@ -9761,7 +9811,7 @@ class DocumentManagementService {
|
|
|
9761
9811
|
async removeAllDocuments(library, version) {
|
|
9762
9812
|
const normalizedVersion = this.normalizeVersion(version);
|
|
9763
9813
|
logger.info(
|
|
9764
|
-
`🗑️ Removing all documents from ${library}@${normalizedVersion || "
|
|
9814
|
+
`🗑️ Removing all documents from ${library}@${normalizedVersion || "latest"} store`
|
|
9765
9815
|
);
|
|
9766
9816
|
const count = await this.store.deletePages(library, normalizedVersion);
|
|
9767
9817
|
logger.info(`🗑️ Deleted ${count} documents`);
|
|
@@ -9792,17 +9842,15 @@ class DocumentManagementService {
|
|
|
9792
9842
|
*/
|
|
9793
9843
|
async removeVersion(library, version) {
|
|
9794
9844
|
const normalizedVersion = this.normalizeVersion(version);
|
|
9795
|
-
logger.debug(`Removing version: ${library}@${normalizedVersion || "
|
|
9845
|
+
logger.debug(`Removing version: ${library}@${normalizedVersion || "latest"}`);
|
|
9796
9846
|
const result = await this.store.removeVersion(library, normalizedVersion, true);
|
|
9797
9847
|
logger.info(`🗑️ Removed ${result.documentsDeleted} documents`);
|
|
9798
9848
|
if (result.versionDeleted && result.libraryDeleted) {
|
|
9799
9849
|
logger.info(`🗑️ Completely removed library ${library} (was last version)`);
|
|
9800
9850
|
} else if (result.versionDeleted) {
|
|
9801
|
-
logger.info(`🗑️ Removed version ${library}@${normalizedVersion || "
|
|
9851
|
+
logger.info(`🗑️ Removed version ${library}@${normalizedVersion || "latest"}`);
|
|
9802
9852
|
} else {
|
|
9803
|
-
logger.warn(
|
|
9804
|
-
`⚠️ Version ${library}@${normalizedVersion || "[no version]"} not found`
|
|
9805
|
-
);
|
|
9853
|
+
logger.warn(`⚠️ Version ${library}@${normalizedVersion || "latest"} not found`);
|
|
9806
9854
|
const libraryRecord = await this.store.getLibrary(library);
|
|
9807
9855
|
if (libraryRecord) {
|
|
9808
9856
|
const versions = await this.store.queryUniqueVersions(library);
|
|
@@ -10538,6 +10586,29 @@ function registerEventsRoute(server, eventBus) {
|
|
|
10538
10586
|
});
|
|
10539
10587
|
});
|
|
10540
10588
|
}
|
|
10589
|
+
const PrimaryButton = ({
|
|
10590
|
+
children,
|
|
10591
|
+
type = "button",
|
|
10592
|
+
class: className = "",
|
|
10593
|
+
disabled = false,
|
|
10594
|
+
...rest
|
|
10595
|
+
}) => {
|
|
10596
|
+
const baseClasses = "w-full flex justify-center py-1.5 px-3 border border-transparent rounded-md shadow-sm text-sm font-medium text-white bg-primary-600 hover:bg-primary-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-primary-500 transition-colors duration-150";
|
|
10597
|
+
const disabledClasses = disabled ? "opacity-50 cursor-not-allowed" : "";
|
|
10598
|
+
const combinedClasses = `${baseClasses} ${disabledClasses} ${className}`.trim();
|
|
10599
|
+
return /* @__PURE__ */ jsx("button", { type, class: combinedClasses, disabled, ...rest, children });
|
|
10600
|
+
};
|
|
10601
|
+
const AddJobButton = () => {
|
|
10602
|
+
return /* @__PURE__ */ jsx(
|
|
10603
|
+
PrimaryButton,
|
|
10604
|
+
{
|
|
10605
|
+
"hx-get": "/web/jobs/new",
|
|
10606
|
+
"hx-target": "#addJobForm",
|
|
10607
|
+
"hx-swap": "innerHTML",
|
|
10608
|
+
children: "Add New Documentation"
|
|
10609
|
+
}
|
|
10610
|
+
);
|
|
10611
|
+
};
|
|
10541
10612
|
const Toast = () => {
|
|
10542
10613
|
return /* @__PURE__ */ jsx(
|
|
10543
10614
|
"div",
|
|
@@ -10666,7 +10737,7 @@ const Layout = ({
|
|
|
10666
10737
|
children,
|
|
10667
10738
|
eventClientConfig
|
|
10668
10739
|
}) => {
|
|
10669
|
-
const versionString = version || "1.
|
|
10740
|
+
const versionString = version || "1.31.1";
|
|
10670
10741
|
const versionInitializer = `versionUpdate({ currentVersion: ${`'${versionString}'`} })`;
|
|
10671
10742
|
return /* @__PURE__ */ jsxs("html", { lang: "en", children: [
|
|
10672
10743
|
/* @__PURE__ */ jsxs("head", { children: [
|
|
@@ -11014,17 +11085,7 @@ function registerIndexRoute(server, config) {
|
|
|
11014
11085
|
}
|
|
11015
11086
|
)
|
|
11016
11087
|
] }),
|
|
11017
|
-
/* @__PURE__ */ jsx("section", { class: "mb-8", children: /* @__PURE__ */ jsx("div", { id: "addJobForm", children: /* @__PURE__ */ jsx(
|
|
11018
|
-
"button",
|
|
11019
|
-
{
|
|
11020
|
-
type: "button",
|
|
11021
|
-
"hx-get": "/web/jobs/new",
|
|
11022
|
-
"hx-target": "#addJobForm",
|
|
11023
|
-
"hx-swap": "innerHTML",
|
|
11024
|
-
class: "w-full flex justify-center py-1.5 px-3 border border-transparent rounded-md shadow-sm text-sm font-medium text-white bg-primary-600 hover:bg-primary-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-primary-500 transition-colors duration-150",
|
|
11025
|
-
children: "Add New Documentation"
|
|
11026
|
-
}
|
|
11027
|
-
) }) }),
|
|
11088
|
+
/* @__PURE__ */ jsx("section", { class: "mb-8", children: /* @__PURE__ */ jsx("div", { id: "addJobForm", children: /* @__PURE__ */ jsx(AddJobButton, {}) }) }),
|
|
11028
11089
|
/* @__PURE__ */ jsxs("div", { children: [
|
|
11029
11090
|
/* @__PURE__ */ jsx("h2", { class: "text-xl font-semibold mb-2 text-gray-900 dark:text-white", children: "Indexed Documentation" }),
|
|
11030
11091
|
/* @__PURE__ */ jsx(
|
|
@@ -11155,10 +11216,12 @@ const ProgressBar = ({ progress, showText = true }) => {
|
|
|
11155
11216
|
) })
|
|
11156
11217
|
] });
|
|
11157
11218
|
};
|
|
11158
|
-
const LoadingSpinner = (
|
|
11219
|
+
const LoadingSpinner = ({
|
|
11220
|
+
class: className = "text-white"
|
|
11221
|
+
}) => /* @__PURE__ */ jsxs(
|
|
11159
11222
|
"svg",
|
|
11160
11223
|
{
|
|
11161
|
-
class:
|
|
11224
|
+
class: `animate-spin h-4 w-4 ${className}`,
|
|
11162
11225
|
xmlns: "http://www.w3.org/2000/svg",
|
|
11163
11226
|
fill: "none",
|
|
11164
11227
|
viewBox: "0 0 24 24",
|
|
@@ -11293,6 +11356,17 @@ function registerJobListRoutes(server, listJobsTool) {
|
|
|
11293
11356
|
return /* @__PURE__ */ jsx(JobList, { jobs: result.jobs });
|
|
11294
11357
|
});
|
|
11295
11358
|
}
|
|
11359
|
+
const AddVersionButton = ({ libraryName }) => {
|
|
11360
|
+
return /* @__PURE__ */ jsx(
|
|
11361
|
+
PrimaryButton,
|
|
11362
|
+
{
|
|
11363
|
+
"hx-get": `/web/libraries/${encodeURIComponent(libraryName)}/add-version-form`,
|
|
11364
|
+
"hx-target": "#add-version-form-container",
|
|
11365
|
+
"hx-swap": "innerHTML",
|
|
11366
|
+
children: "Add New Version"
|
|
11367
|
+
}
|
|
11368
|
+
);
|
|
11369
|
+
};
|
|
11296
11370
|
const Alert = ({ type, title, message }) => {
|
|
11297
11371
|
let iconSvg;
|
|
11298
11372
|
let colorClasses;
|
|
@@ -11437,17 +11511,39 @@ const Tooltip = ({ text, position = "top" }) => {
|
|
|
11437
11511
|
);
|
|
11438
11512
|
};
|
|
11439
11513
|
const ScrapeFormContent = ({
|
|
11440
|
-
defaultExcludePatterns
|
|
11514
|
+
defaultExcludePatterns,
|
|
11515
|
+
initialValues,
|
|
11516
|
+
mode = "new"
|
|
11441
11517
|
}) => {
|
|
11442
|
-
const
|
|
11518
|
+
const isAddVersionMode = mode === "add-version";
|
|
11519
|
+
const urlValue = initialValues?.url || "";
|
|
11520
|
+
const libraryValue = initialValues?.library || "";
|
|
11521
|
+
const maxPagesValue = initialValues?.maxPages?.toString() || "";
|
|
11522
|
+
const maxDepthValue = initialValues?.maxDepth?.toString() || "";
|
|
11523
|
+
const scopeValue = initialValues?.scope || "subpages";
|
|
11524
|
+
const includePatternsValue = initialValues?.includePatterns || "";
|
|
11525
|
+
const scrapeModeValue = initialValues?.scrapeMode || ScrapeMode.Auto;
|
|
11526
|
+
const followRedirectsValue = initialValues?.followRedirects ?? true;
|
|
11527
|
+
const ignoreErrorsValue = initialValues?.ignoreErrors ?? true;
|
|
11528
|
+
const excludePatternsText = initialValues?.excludePatterns !== void 0 ? initialValues.excludePatterns : defaultExcludePatterns?.join("\n") || "";
|
|
11529
|
+
const headersJson = JSON.stringify(initialValues?.headers || []);
|
|
11530
|
+
const closeButtonAttrs = isAddVersionMode ? {
|
|
11531
|
+
"hx-get": `/web/libraries/${encodeURIComponent(libraryValue)}/add-version-button`,
|
|
11532
|
+
"hx-target": "#add-version-form-container",
|
|
11533
|
+
"hx-swap": "innerHTML"
|
|
11534
|
+
} : {
|
|
11535
|
+
"hx-get": "/web/jobs/new-button",
|
|
11536
|
+
"hx-target": "#addJobForm",
|
|
11537
|
+
"hx-swap": "innerHTML"
|
|
11538
|
+
};
|
|
11539
|
+
const formTarget = isAddVersionMode ? "#add-version-form-container" : "#addJobForm";
|
|
11540
|
+
const title = isAddVersionMode ? "Add New Version" : "Add New Documentation";
|
|
11443
11541
|
return /* @__PURE__ */ jsxs("div", { class: "mt-4 p-4 bg-white dark:bg-gray-800 rounded-lg shadow border border-gray-300 dark:border-gray-600 relative animate-[fadeSlideIn_0.2s_ease-out]", children: [
|
|
11444
11542
|
/* @__PURE__ */ jsx(
|
|
11445
11543
|
"button",
|
|
11446
11544
|
{
|
|
11447
11545
|
type: "button",
|
|
11448
|
-
|
|
11449
|
-
"hx-target": "#addJobForm",
|
|
11450
|
-
"hx-swap": "innerHTML",
|
|
11546
|
+
...closeButtonAttrs,
|
|
11451
11547
|
class: "absolute top-3 right-3 p-1 text-gray-400 hover:text-gray-600 dark:hover:text-gray-300 rounded-full hover:bg-gray-100 dark:hover:bg-gray-700 transition-colors duration-150",
|
|
11452
11548
|
title: "Close",
|
|
11453
11549
|
children: /* @__PURE__ */ jsx(
|
|
@@ -11471,16 +11567,20 @@ const ScrapeFormContent = ({
|
|
|
11471
11567
|
)
|
|
11472
11568
|
}
|
|
11473
11569
|
),
|
|
11474
|
-
/* @__PURE__ */ jsx("h3", { class: "text-xl font-semibold text-gray-900 dark:text-white mb-2 pr-8", children:
|
|
11570
|
+
/* @__PURE__ */ jsx("h3", { class: "text-xl font-semibold text-gray-900 dark:text-white mb-2 pr-8", children: title }),
|
|
11475
11571
|
/* @__PURE__ */ jsxs(
|
|
11476
11572
|
"form",
|
|
11477
11573
|
{
|
|
11478
11574
|
"hx-post": "/web/jobs/scrape",
|
|
11479
|
-
"hx-target":
|
|
11575
|
+
"hx-target": formTarget,
|
|
11480
11576
|
"hx-swap": "innerHTML",
|
|
11481
11577
|
class: "space-y-2",
|
|
11482
|
-
"
|
|
11578
|
+
"data-initial-url": urlValue,
|
|
11579
|
+
"data-initial-headers": headersJson,
|
|
11580
|
+
"x-data": "{\n url: '',\n hasPath: false,\n headers: [],\n checkUrlPath() {\n try {\n const url = new URL(this.url);\n this.hasPath = url.pathname !== '/' && url.pathname !== '';\n } catch (e) {\n this.hasPath = false;\n }\n }\n }",
|
|
11581
|
+
"x-init": "\n url = $el.dataset.initialUrl || '';\n headers = JSON.parse($el.dataset.initialHeaders || '[]');\n checkUrlPath();\n ",
|
|
11483
11582
|
children: [
|
|
11583
|
+
/* @__PURE__ */ jsx("input", { type: "hidden", name: "formMode", value: mode }),
|
|
11484
11584
|
/* @__PURE__ */ jsxs("div", { children: [
|
|
11485
11585
|
/* @__PURE__ */ jsxs("div", { class: "flex items-center", children: [
|
|
11486
11586
|
/* @__PURE__ */ jsx(
|
|
@@ -11521,6 +11621,7 @@ const ScrapeFormContent = ({
|
|
|
11521
11621
|
"x-model": "url",
|
|
11522
11622
|
"x-on:input": "checkUrlPath",
|
|
11523
11623
|
"x-on:paste": "$nextTick(() => checkUrlPath())",
|
|
11624
|
+
placeholder: "https://docs.example.com/library/",
|
|
11524
11625
|
class: "mt-0.5 block w-full px-2 py-1 border border-gray-300 dark:border-gray-600 rounded-md shadow-sm focus:outline-none focus:ring-primary-500 focus:border-primary-500 sm:text-sm bg-white dark:bg-gray-700 text-gray-900 dark:text-white"
|
|
11525
11626
|
}
|
|
11526
11627
|
),
|
|
@@ -11555,13 +11656,18 @@ const ScrapeFormContent = ({
|
|
|
11555
11656
|
),
|
|
11556
11657
|
/* @__PURE__ */ jsx(Tooltip, { text: "The name of the library you're documenting. This will be used when searching." })
|
|
11557
11658
|
] }),
|
|
11558
|
-
/* @__PURE__ */
|
|
11659
|
+
isAddVersionMode ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
11660
|
+
/* @__PURE__ */ jsx("input", { type: "hidden", name: "library", value: libraryValue }),
|
|
11661
|
+
/* @__PURE__ */ jsx("div", { class: "mt-0.5 px-2 py-1 text-sm text-gray-700 dark:text-gray-300 bg-gray-100 dark:bg-gray-700 rounded-md border border-gray-300 dark:border-gray-600", children: /* @__PURE__ */ jsx("span", { safe: true, children: libraryValue }) })
|
|
11662
|
+
] }) : /* @__PURE__ */ jsx(
|
|
11559
11663
|
"input",
|
|
11560
11664
|
{
|
|
11561
11665
|
type: "text",
|
|
11562
11666
|
name: "library",
|
|
11563
11667
|
id: "library",
|
|
11564
11668
|
required: true,
|
|
11669
|
+
value: libraryValue,
|
|
11670
|
+
placeholder: "e.g. react, vue, express",
|
|
11565
11671
|
class: "mt-0.5 block w-full px-2 py-1 border border-gray-300 dark:border-gray-600 rounded-md shadow-sm focus:outline-none focus:ring-primary-500 focus:border-primary-500 sm:text-sm bg-white dark:bg-gray-700 text-gray-900 dark:text-white"
|
|
11566
11672
|
}
|
|
11567
11673
|
)
|
|
@@ -11576,7 +11682,7 @@ const ScrapeFormContent = ({
|
|
|
11576
11682
|
children: "Version (optional)"
|
|
11577
11683
|
}
|
|
11578
11684
|
),
|
|
11579
|
-
/* @__PURE__ */ jsx(Tooltip, { text: "Specify the version of the library documentation you're indexing. This allows for version-specific searches." })
|
|
11685
|
+
/* @__PURE__ */ jsx(Tooltip, { text: "Specify the version of the library documentation you're indexing (e.g. 2.0.0). Leave empty or enter 'latest' to index without a specific version. This allows for version-specific searches." })
|
|
11580
11686
|
] }),
|
|
11581
11687
|
/* @__PURE__ */ jsx(
|
|
11582
11688
|
"input",
|
|
@@ -11584,6 +11690,7 @@ const ScrapeFormContent = ({
|
|
|
11584
11690
|
type: "text",
|
|
11585
11691
|
name: "version",
|
|
11586
11692
|
id: "version",
|
|
11693
|
+
placeholder: "e.g. 2.0.0 or leave empty for latest",
|
|
11587
11694
|
class: "mt-0.5 block w-full max-w-sm px-2 py-1 border border-gray-300 dark:border-gray-600 rounded-md shadow-sm focus:outline-none focus:ring-primary-500 focus:border-primary-500 sm:text-sm bg-white dark:bg-gray-700 text-gray-900 dark:text-white"
|
|
11588
11695
|
}
|
|
11589
11696
|
)
|
|
@@ -11592,7 +11699,9 @@ const ScrapeFormContent = ({
|
|
|
11592
11699
|
"div",
|
|
11593
11700
|
{
|
|
11594
11701
|
class: "bg-gray-50 dark:bg-gray-900 p-2 rounded-md",
|
|
11595
|
-
"
|
|
11702
|
+
"data-should-open": isAddVersionMode && (maxPagesValue || maxDepthValue || scopeValue !== "subpages" || includePatternsValue || excludePatternsText || scrapeModeValue !== ScrapeMode.Auto) ? "true" : "false",
|
|
11703
|
+
"x-data": "{ open: false }",
|
|
11704
|
+
"x-init": "open = $el.dataset.shouldOpen === 'true'",
|
|
11596
11705
|
children: [
|
|
11597
11706
|
/* @__PURE__ */ jsxs(
|
|
11598
11707
|
"button",
|
|
@@ -11645,6 +11754,7 @@ const ScrapeFormContent = ({
|
|
|
11645
11754
|
id: "maxPages",
|
|
11646
11755
|
min: "1",
|
|
11647
11756
|
placeholder: "1000",
|
|
11757
|
+
value: maxPagesValue,
|
|
11648
11758
|
class: "mt-0.5 block w-full max-w-sm px-2 py-1 border border-gray-300 dark:border-gray-600 rounded-md shadow-sm focus:outline-none focus:ring-primary-500 focus:border-primary-500 sm:text-sm bg-white dark:bg-gray-700 text-gray-900 dark:text-white"
|
|
11649
11759
|
}
|
|
11650
11760
|
)
|
|
@@ -11669,6 +11779,7 @@ const ScrapeFormContent = ({
|
|
|
11669
11779
|
id: "maxDepth",
|
|
11670
11780
|
min: "0",
|
|
11671
11781
|
placeholder: "3",
|
|
11782
|
+
value: maxDepthValue,
|
|
11672
11783
|
class: "mt-0.5 block w-full max-w-sm px-2 py-1 border border-gray-300 dark:border-gray-600 rounded-md shadow-sm focus:outline-none focus:ring-primary-500 focus:border-primary-500 sm:text-sm bg-white dark:bg-gray-700 text-gray-900 dark:text-white"
|
|
11673
11784
|
}
|
|
11674
11785
|
)
|
|
@@ -11704,9 +11815,9 @@ const ScrapeFormContent = ({
|
|
|
11704
11815
|
id: "scope",
|
|
11705
11816
|
class: "mt-0.5 block w-full max-w-sm pl-2 pr-10 py-1 text-base border border-gray-300 dark:border-gray-600 focus:outline-none focus:ring-primary-500 focus:border-primary-500 sm:text-sm rounded-md bg-white dark:bg-gray-700 text-gray-900 dark:text-white",
|
|
11706
11817
|
children: [
|
|
11707
|
-
/* @__PURE__ */ jsx("option", { value: "subpages", selected:
|
|
11708
|
-
/* @__PURE__ */ jsx("option", { value: "hostname", children: "Hostname" }),
|
|
11709
|
-
/* @__PURE__ */ jsx("option", { value: "domain", children: "Domain" })
|
|
11818
|
+
/* @__PURE__ */ jsx("option", { value: "subpages", selected: scopeValue === "subpages", children: "Subpages (Default)" }),
|
|
11819
|
+
/* @__PURE__ */ jsx("option", { value: "hostname", selected: scopeValue === "hostname", children: "Hostname" }),
|
|
11820
|
+
/* @__PURE__ */ jsx("option", { value: "domain", selected: scopeValue === "domain", children: "Domain" })
|
|
11710
11821
|
]
|
|
11711
11822
|
}
|
|
11712
11823
|
)
|
|
@@ -11730,7 +11841,9 @@ const ScrapeFormContent = ({
|
|
|
11730
11841
|
id: "includePatterns",
|
|
11731
11842
|
rows: "2",
|
|
11732
11843
|
placeholder: "e.g. docs/* or /api\\/v1.*/",
|
|
11733
|
-
class: "mt-0.5 block w-full max-w-sm px-2 py-1 border border-gray-300 dark:border-gray-600 rounded-md shadow-sm focus:outline-none focus:ring-primary-500 focus:border-primary-500 sm:text-sm bg-white dark:bg-gray-700 text-gray-900 dark:text-white"
|
|
11844
|
+
class: "mt-0.5 block w-full max-w-sm px-2 py-1 border border-gray-300 dark:border-gray-600 rounded-md shadow-sm focus:outline-none focus:ring-primary-500 focus:border-primary-500 sm:text-sm bg-white dark:bg-gray-700 text-gray-900 dark:text-white",
|
|
11845
|
+
safe: true,
|
|
11846
|
+
children: includePatternsValue
|
|
11734
11847
|
}
|
|
11735
11848
|
)
|
|
11736
11849
|
] }),
|
|
@@ -11754,10 +11867,10 @@ const ScrapeFormContent = ({
|
|
|
11754
11867
|
rows: "5",
|
|
11755
11868
|
safe: true,
|
|
11756
11869
|
class: "mt-0.5 block w-full max-w-sm px-2 py-1 border border-gray-300 dark:border-gray-600 rounded-md shadow-sm focus:outline-none focus:ring-primary-500 focus:border-primary-500 sm:text-sm bg-white dark:bg-gray-700 text-gray-900 dark:text-white font-mono text-xs",
|
|
11757
|
-
children:
|
|
11870
|
+
children: excludePatternsText
|
|
11758
11871
|
}
|
|
11759
11872
|
),
|
|
11760
|
-
/* @__PURE__ */ jsx("p", { class: "mt-1 text-xs text-gray-500 dark:text-gray-400", children: "Default patterns are pre-filled. Edit to customize or clear to exclude nothing." })
|
|
11873
|
+
/* @__PURE__ */ jsx("p", { class: "mt-1 text-xs text-gray-500 dark:text-gray-400", children: isAddVersionMode ? "Patterns from previous version. Edit as needed." : "Default patterns are pre-filled. Edit to customize or clear to exclude nothing." })
|
|
11761
11874
|
] }),
|
|
11762
11875
|
/* @__PURE__ */ jsxs("div", { children: [
|
|
11763
11876
|
/* @__PURE__ */ jsxs("div", { class: "flex items-center", children: [
|
|
@@ -11787,9 +11900,30 @@ const ScrapeFormContent = ({
|
|
|
11787
11900
|
id: "scrapeMode",
|
|
11788
11901
|
class: "mt-0.5 block w-full max-w-sm pl-2 pr-10 py-1 text-base border border-gray-300 dark:border-gray-600 focus:outline-none focus:ring-primary-500 focus:border-primary-500 sm:text-sm rounded-md bg-white dark:bg-gray-700 text-gray-900 dark:text-white",
|
|
11789
11902
|
children: [
|
|
11790
|
-
/* @__PURE__ */ jsx(
|
|
11791
|
-
|
|
11792
|
-
|
|
11903
|
+
/* @__PURE__ */ jsx(
|
|
11904
|
+
"option",
|
|
11905
|
+
{
|
|
11906
|
+
value: ScrapeMode.Auto,
|
|
11907
|
+
selected: scrapeModeValue === ScrapeMode.Auto,
|
|
11908
|
+
children: "Auto (Default)"
|
|
11909
|
+
}
|
|
11910
|
+
),
|
|
11911
|
+
/* @__PURE__ */ jsx(
|
|
11912
|
+
"option",
|
|
11913
|
+
{
|
|
11914
|
+
value: ScrapeMode.Fetch,
|
|
11915
|
+
selected: scrapeModeValue === ScrapeMode.Fetch,
|
|
11916
|
+
children: "Fetch"
|
|
11917
|
+
}
|
|
11918
|
+
),
|
|
11919
|
+
/* @__PURE__ */ jsx(
|
|
11920
|
+
"option",
|
|
11921
|
+
{
|
|
11922
|
+
value: ScrapeMode.Playwright,
|
|
11923
|
+
selected: scrapeModeValue === ScrapeMode.Playwright,
|
|
11924
|
+
children: "Playwright"
|
|
11925
|
+
}
|
|
11926
|
+
)
|
|
11793
11927
|
]
|
|
11794
11928
|
}
|
|
11795
11929
|
)
|
|
@@ -11858,7 +11992,7 @@ const ScrapeFormContent = ({
|
|
|
11858
11992
|
id: "followRedirects",
|
|
11859
11993
|
name: "followRedirects",
|
|
11860
11994
|
type: "checkbox",
|
|
11861
|
-
checked:
|
|
11995
|
+
checked: followRedirectsValue,
|
|
11862
11996
|
class: "h-4 w-4 text-primary-600 focus:ring-primary-500 border-gray-300 dark:border-gray-600 rounded bg-white dark:bg-gray-700"
|
|
11863
11997
|
}
|
|
11864
11998
|
),
|
|
@@ -11878,7 +12012,7 @@ const ScrapeFormContent = ({
|
|
|
11878
12012
|
id: "ignoreErrors",
|
|
11879
12013
|
name: "ignoreErrors",
|
|
11880
12014
|
type: "checkbox",
|
|
11881
|
-
checked:
|
|
12015
|
+
checked: ignoreErrorsValue,
|
|
11882
12016
|
class: "h-4 w-4 text-primary-600 focus:ring-primary-500 border-gray-300 dark:border-gray-600 rounded bg-white dark:bg-gray-700"
|
|
11883
12017
|
}
|
|
11884
12018
|
),
|
|
@@ -12009,23 +12143,12 @@ function getEffectiveExclusionPatterns(userPatterns) {
|
|
|
12009
12143
|
}
|
|
12010
12144
|
return DEFAULT_EXCLUSION_PATTERNS;
|
|
12011
12145
|
}
|
|
12012
|
-
const ScrapeFormButton = () => /* @__PURE__ */ jsx(
|
|
12013
|
-
"button",
|
|
12014
|
-
{
|
|
12015
|
-
type: "button",
|
|
12016
|
-
"hx-get": "/web/jobs/new",
|
|
12017
|
-
"hx-target": "#addJobForm",
|
|
12018
|
-
"hx-swap": "innerHTML",
|
|
12019
|
-
class: "w-full flex justify-center py-1.5 px-3 border border-transparent rounded-md shadow-sm text-sm font-medium text-white bg-primary-600 hover:bg-primary-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-primary-500 transition-colors duration-150",
|
|
12020
|
-
children: "Add New Documentation"
|
|
12021
|
-
}
|
|
12022
|
-
);
|
|
12023
12146
|
function registerNewJobRoutes(server, scrapeTool) {
|
|
12024
12147
|
server.get("/web/jobs/new", async () => {
|
|
12025
12148
|
return /* @__PURE__ */ jsx(ScrapeForm, { defaultExcludePatterns: DEFAULT_EXCLUSION_PATTERNS });
|
|
12026
12149
|
});
|
|
12027
12150
|
server.get("/web/jobs/new-button", async () => {
|
|
12028
|
-
return /* @__PURE__ */ jsx(
|
|
12151
|
+
return /* @__PURE__ */ jsx(AddJobButton, {});
|
|
12029
12152
|
});
|
|
12030
12153
|
server.post(
|
|
12031
12154
|
"/web/jobs/scrape",
|
|
@@ -12061,11 +12184,11 @@ function registerNewJobRoutes(server, scrapeTool) {
|
|
|
12061
12184
|
}
|
|
12062
12185
|
);
|
|
12063
12186
|
}
|
|
12187
|
+
const normalizedVersion = !body.version || body.version.trim() === "" || body.version.trim().toLowerCase() === "latest" ? null : body.version.trim();
|
|
12064
12188
|
const scrapeOptions = {
|
|
12065
12189
|
url: body.url,
|
|
12066
12190
|
library: body.library,
|
|
12067
|
-
version:
|
|
12068
|
-
// Handle empty string as null
|
|
12191
|
+
version: normalizedVersion,
|
|
12069
12192
|
waitForCompletion: false,
|
|
12070
12193
|
// Don't wait in UI
|
|
12071
12194
|
options: {
|
|
@@ -12084,16 +12207,20 @@ function registerNewJobRoutes(server, scrapeTool) {
|
|
|
12084
12207
|
};
|
|
12085
12208
|
const result = await scrapeTool.execute(scrapeOptions);
|
|
12086
12209
|
if ("jobId" in result) {
|
|
12210
|
+
const versionDisplay = normalizedVersion || "latest";
|
|
12087
12211
|
reply.header(
|
|
12088
12212
|
"HX-Trigger",
|
|
12089
12213
|
JSON.stringify({
|
|
12090
12214
|
toast: {
|
|
12091
|
-
message:
|
|
12215
|
+
message: `Indexing started for ${body.library}@${versionDisplay}`,
|
|
12092
12216
|
type: "success"
|
|
12093
12217
|
}
|
|
12094
12218
|
})
|
|
12095
12219
|
);
|
|
12096
|
-
|
|
12220
|
+
if (body.formMode === "add-version") {
|
|
12221
|
+
return /* @__PURE__ */ jsx(AddVersionButton, { libraryName: body.library });
|
|
12222
|
+
}
|
|
12223
|
+
return /* @__PURE__ */ jsx(AddJobButton, {});
|
|
12097
12224
|
}
|
|
12098
12225
|
return /* @__PURE__ */ jsx(Alert, { type: "warning", message: "Job finished unexpectedly quickly." });
|
|
12099
12226
|
} catch (error) {
|
|
@@ -12119,15 +12246,16 @@ function registerNewJobRoutes(server, scrapeTool) {
|
|
|
12119
12246
|
const VersionDetailsRow = ({
|
|
12120
12247
|
version,
|
|
12121
12248
|
libraryName,
|
|
12122
|
-
showDelete = true
|
|
12123
|
-
|
|
12249
|
+
showDelete = true,
|
|
12250
|
+
showRefresh = false
|
|
12124
12251
|
}) => {
|
|
12125
12252
|
const indexedDate = version.indexedAt ? new Date(version.indexedAt).toLocaleDateString() : "N/A";
|
|
12126
|
-
const versionLabel = version.ref.version || "
|
|
12253
|
+
const versionLabel = version.ref.version || "Latest";
|
|
12127
12254
|
const versionParam = version.ref.version || "";
|
|
12128
12255
|
const sanitizedLibraryName = libraryName.replace(/[^a-zA-Z0-9-_]/g, "-");
|
|
12129
12256
|
const sanitizedVersionParam = versionParam.replace(/[^a-zA-Z0-9-_]/g, "-");
|
|
12130
12257
|
const rowId = `row-${sanitizedLibraryName}-${sanitizedVersionParam}`;
|
|
12258
|
+
const initialIsRefreshing = isActiveStatus(version.status);
|
|
12131
12259
|
const defaultStateClasses = "text-red-700 border border-red-700 hover:bg-red-700 hover:text-white focus:ring-4 focus:outline-none focus:ring-red-300 dark:border-red-500 dark:text-red-500 dark:hover:text-white dark:focus:ring-red-800 dark:hover:bg-red-500";
|
|
12132
12260
|
const confirmingStateClasses = "bg-red-600 text-white border-red-600 focus:ring-4 focus:outline-none focus:ring-red-300 dark:bg-red-700 dark:border-red-700 dark:focus:ring-red-800";
|
|
12133
12261
|
return (
|
|
@@ -12139,14 +12267,16 @@ const VersionDetailsRow = ({
|
|
|
12139
12267
|
class: "flex justify-between items-center py-1 border-b border-gray-200 dark:border-gray-600 last:border-b-0",
|
|
12140
12268
|
"data-library-name": libraryName,
|
|
12141
12269
|
"data-version-param": versionParam,
|
|
12142
|
-
"
|
|
12270
|
+
"data-is-refreshing": initialIsRefreshing ? "true" : "false",
|
|
12271
|
+
"x-data": "{ \n library: $el.dataset.libraryName, \n version: $el.dataset.versionParam, \n confirming: $el.dataset.confirming === 'true', \n isDeleting: false,\n isRefreshing: $el.dataset.isRefreshing === 'true',\n setRefreshing(val) {\n this.isRefreshing = !!val;\n this.$el.dataset.isRefreshing = val ? 'true' : 'false';\n },\n init() {\n const rowId = this.$el.id;\n const myLibrary = this.library;\n const myVersion = this.version;\n \n document.body.addEventListener('job-status-change', (e) => {\n const job = e.detail;\n const jobVersion = job.version || '';\n if (job.library === myLibrary && jobVersion === myVersion) {\n const newValue = ['queued', 'running'].includes(job.status);\n const el = document.getElementById(rowId);\n if (el) {\n el.dispatchEvent(new CustomEvent('set-refreshing', { detail: newValue, bubbles: true }));\n }\n }\n });\n }\n }",
|
|
12272
|
+
"x-on:set-refreshing": "setRefreshing($event.detail)",
|
|
12143
12273
|
children: [
|
|
12144
12274
|
/* @__PURE__ */ jsx(
|
|
12145
12275
|
"span",
|
|
12146
12276
|
{
|
|
12147
12277
|
class: "text-sm text-gray-900 dark:text-white w-1/4 truncate",
|
|
12148
12278
|
title: versionLabel,
|
|
12149
|
-
children: version.ref.version ? /* @__PURE__ */ jsx(VersionBadge, { version: version.ref.version }) : /* @__PURE__ */ jsx("span", { children: "
|
|
12279
|
+
children: version.ref.version ? /* @__PURE__ */ jsx(VersionBadge, { version: version.ref.version }) : /* @__PURE__ */ jsx("span", { class: "text-gray-600 dark:text-gray-400", children: "Latest" })
|
|
12150
12280
|
}
|
|
12151
12281
|
),
|
|
12152
12282
|
/* @__PURE__ */ jsxs("div", { class: "flex space-x-2 text-sm text-gray-600 dark:text-gray-400 w-3/4 justify-end items-center", children: [
|
|
@@ -12166,66 +12296,117 @@ const VersionDetailsRow = ({
|
|
|
12166
12296
|
/* @__PURE__ */ jsx("span", { class: "font-semibold", safe: true, children: indexedDate })
|
|
12167
12297
|
] })
|
|
12168
12298
|
] }),
|
|
12169
|
-
|
|
12170
|
-
|
|
12171
|
-
|
|
12172
|
-
|
|
12173
|
-
|
|
12174
|
-
|
|
12175
|
-
|
|
12176
|
-
|
|
12177
|
-
|
|
12178
|
-
|
|
12179
|
-
|
|
12180
|
-
|
|
12181
|
-
|
|
12182
|
-
|
|
12183
|
-
|
|
12184
|
-
|
|
12185
|
-
|
|
12186
|
-
|
|
12187
|
-
|
|
12188
|
-
|
|
12189
|
-
|
|
12190
|
-
|
|
12191
|
-
|
|
12192
|
-
|
|
12193
|
-
|
|
12194
|
-
|
|
12195
|
-
|
|
12196
|
-
|
|
12197
|
-
|
|
12198
|
-
|
|
12199
|
-
|
|
12200
|
-
|
|
12201
|
-
|
|
12202
|
-
}
|
|
12203
|
-
|
|
12204
|
-
|
|
12205
|
-
|
|
12206
|
-
|
|
12207
|
-
|
|
12208
|
-
|
|
12209
|
-
|
|
12210
|
-
|
|
12211
|
-
|
|
12212
|
-
|
|
12213
|
-
|
|
12214
|
-
|
|
12215
|
-
|
|
12216
|
-
|
|
12299
|
+
/* @__PURE__ */ jsxs("div", { class: "flex items-center ml-2 space-x-1", children: [
|
|
12300
|
+
showRefresh && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
12301
|
+
/* @__PURE__ */ jsx("template", { "x-if": "!isRefreshing", children: /* @__PURE__ */ jsxs(
|
|
12302
|
+
"button",
|
|
12303
|
+
{
|
|
12304
|
+
type: "button",
|
|
12305
|
+
class: "font-medium rounded-lg text-sm p-1 w-6 h-6 text-center inline-flex items-center justify-center transition-colors duration-150 ease-in-out text-gray-500 border border-gray-300 hover:bg-gray-100 hover:text-gray-700 focus:ring-4 focus:outline-none focus:ring-gray-200 dark:border-gray-600 dark:text-gray-400 dark:hover:text-white dark:focus:ring-gray-700 dark:hover:bg-gray-600",
|
|
12306
|
+
title: "Refresh this version (re-scrape changed pages)",
|
|
12307
|
+
"x-on:click": "\n isRefreshing = true;\n $root.dataset.isRefreshing = 'true';\n $el.dispatchEvent(new CustomEvent('trigger-refresh', { bubbles: true }));\n ",
|
|
12308
|
+
"hx-post": `/web/libraries/${encodeURIComponent(libraryName)}/versions/${encodeURIComponent(versionParam)}/refresh`,
|
|
12309
|
+
"hx-swap": "none",
|
|
12310
|
+
"hx-trigger": "trigger-refresh",
|
|
12311
|
+
children: [
|
|
12312
|
+
/* @__PURE__ */ jsx(
|
|
12313
|
+
"svg",
|
|
12314
|
+
{
|
|
12315
|
+
class: "w-4 h-4",
|
|
12316
|
+
"aria-hidden": "true",
|
|
12317
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
12318
|
+
fill: "none",
|
|
12319
|
+
viewBox: "0 0 24 24",
|
|
12320
|
+
children: /* @__PURE__ */ jsx(
|
|
12321
|
+
"path",
|
|
12322
|
+
{
|
|
12323
|
+
stroke: "currentColor",
|
|
12324
|
+
"stroke-linecap": "round",
|
|
12325
|
+
"stroke-linejoin": "round",
|
|
12326
|
+
"stroke-width": "2",
|
|
12327
|
+
d: "M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15"
|
|
12328
|
+
}
|
|
12329
|
+
)
|
|
12330
|
+
}
|
|
12331
|
+
),
|
|
12332
|
+
/* @__PURE__ */ jsx("span", { class: "sr-only", children: "Refresh version" })
|
|
12333
|
+
]
|
|
12334
|
+
}
|
|
12335
|
+
) }),
|
|
12336
|
+
/* @__PURE__ */ jsx("template", { "x-if": "isRefreshing", children: /* @__PURE__ */ jsxs(
|
|
12337
|
+
"button",
|
|
12338
|
+
{
|
|
12339
|
+
type: "button",
|
|
12340
|
+
class: "font-medium rounded-lg text-sm p-1 w-6 h-6 text-center inline-flex items-center justify-center transition-colors duration-150 ease-in-out text-gray-500 border border-gray-300 dark:border-gray-600 dark:text-gray-400",
|
|
12341
|
+
title: "Refresh in progress...",
|
|
12342
|
+
disabled: true,
|
|
12343
|
+
children: [
|
|
12344
|
+
/* @__PURE__ */ jsx(LoadingSpinner, { class: "text-gray-500 dark:text-gray-400" }),
|
|
12345
|
+
/* @__PURE__ */ jsx("span", { class: "sr-only", children: "Refreshing..." })
|
|
12346
|
+
]
|
|
12347
|
+
}
|
|
12348
|
+
) })
|
|
12349
|
+
] }),
|
|
12350
|
+
showDelete && /* @__PURE__ */ jsxs(
|
|
12351
|
+
"button",
|
|
12352
|
+
{
|
|
12353
|
+
type: "button",
|
|
12354
|
+
class: "font-medium rounded-lg text-sm p-1 min-w-6 h-6 text-center inline-flex items-center justify-center transition-colors duration-150 ease-in-out",
|
|
12355
|
+
title: "Remove this version",
|
|
12356
|
+
"x-bind:class": `confirming ? '${confirmingStateClasses}' : '${defaultStateClasses}'`,
|
|
12357
|
+
"x-bind:disabled": "isDeleting",
|
|
12358
|
+
"x-on:click": "\n if (confirming) {\n isDeleting = true;\n window.confirmationManager.clear($root.id);\n $el.dispatchEvent(new CustomEvent('confirmed-delete', { bubbles: true }));\n } else {\n confirming = true;\n isDeleting = false;\n window.confirmationManager.start($root.id);\n }\n ",
|
|
12359
|
+
"hx-delete": `/web/libraries/${encodeURIComponent(libraryName)}/versions/${encodeURIComponent(versionParam)}`,
|
|
12360
|
+
"hx-target": `#${rowId}`,
|
|
12361
|
+
"hx-swap": "outerHTML",
|
|
12362
|
+
"hx-trigger": "confirmed-delete",
|
|
12363
|
+
children: [
|
|
12364
|
+
/* @__PURE__ */ jsxs("span", { "x-show": "!confirming && !isDeleting", children: [
|
|
12365
|
+
/* @__PURE__ */ jsx(
|
|
12366
|
+
"svg",
|
|
12367
|
+
{
|
|
12368
|
+
class: "w-4 h-4",
|
|
12369
|
+
"aria-hidden": "true",
|
|
12370
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
12371
|
+
fill: "none",
|
|
12372
|
+
viewBox: "0 0 18 20",
|
|
12373
|
+
children: /* @__PURE__ */ jsx(
|
|
12374
|
+
"path",
|
|
12375
|
+
{
|
|
12376
|
+
stroke: "currentColor",
|
|
12377
|
+
"stroke-linecap": "round",
|
|
12378
|
+
"stroke-linejoin": "round",
|
|
12379
|
+
"stroke-width": "2",
|
|
12380
|
+
d: "M1 5h16M7 8v8m4-8v8M7 1h4a1 1 0 0 1 1 1v3H6V2a1 1 0 0 1-1-1ZM3 5h12v13a1 1 0 0 1-1 1H4a1 1 0 0 1-1-1V5Z"
|
|
12381
|
+
}
|
|
12382
|
+
)
|
|
12383
|
+
}
|
|
12384
|
+
),
|
|
12385
|
+
/* @__PURE__ */ jsx("span", { class: "sr-only", children: "Remove version" })
|
|
12386
|
+
] }),
|
|
12387
|
+
/* @__PURE__ */ jsxs("span", { "x-show": "confirming && !isDeleting", class: "mx-1", children: [
|
|
12388
|
+
"Confirm?",
|
|
12389
|
+
/* @__PURE__ */ jsx("span", { class: "sr-only", children: "Confirm delete" })
|
|
12390
|
+
] }),
|
|
12391
|
+
/* @__PURE__ */ jsxs("span", { "x-show": "isDeleting", children: [
|
|
12392
|
+
/* @__PURE__ */ jsx(LoadingSpinner, {}),
|
|
12393
|
+
/* @__PURE__ */ jsx("span", { class: "sr-only", children: "Loading..." })
|
|
12394
|
+
] })
|
|
12395
|
+
]
|
|
12396
|
+
}
|
|
12397
|
+
)
|
|
12398
|
+
] })
|
|
12217
12399
|
]
|
|
12218
12400
|
}
|
|
12219
12401
|
)
|
|
12220
12402
|
);
|
|
12221
12403
|
};
|
|
12222
12404
|
const LibraryDetailCard = ({ library }) => {
|
|
12223
|
-
const versions = library.versions
|
|
12405
|
+
const versions = library.versions || [];
|
|
12224
12406
|
const latestVersion = versions[0];
|
|
12225
|
-
return (
|
|
12226
|
-
|
|
12227
|
-
|
|
12228
|
-
/* @__PURE__ */ jsx("h3", { class: "text-lg font-medium text-gray-900 dark:text-white mb-1", children: /* @__PURE__ */ jsx("span", { safe: true, children: library.name }) }),
|
|
12407
|
+
return /* @__PURE__ */ jsxs("div", { class: "block p-4 bg-white dark:bg-gray-800 rounded-lg shadow-sm border border-gray-300 dark:border-gray-600 mb-4", children: [
|
|
12408
|
+
/* @__PURE__ */ jsx("div", { class: "flex justify-between items-start mb-1", children: /* @__PURE__ */ jsxs("div", { children: [
|
|
12409
|
+
/* @__PURE__ */ jsx("h3", { class: "text-lg font-medium text-gray-900 dark:text-white", children: /* @__PURE__ */ jsx("span", { safe: true, children: library.name }) }),
|
|
12229
12410
|
latestVersion?.sourceUrl ? /* @__PURE__ */ jsx("div", { class: "text-sm text-gray-500 dark:text-gray-400", children: /* @__PURE__ */ jsx(
|
|
12230
12411
|
"a",
|
|
12231
12412
|
{
|
|
@@ -12235,31 +12416,43 @@ const LibraryDetailCard = ({ library }) => {
|
|
|
12235
12416
|
safe: true,
|
|
12236
12417
|
children: latestVersion.sourceUrl
|
|
12237
12418
|
}
|
|
12238
|
-
) }) : null
|
|
12239
|
-
|
|
12240
|
-
|
|
12241
|
-
|
|
12242
|
-
|
|
12243
|
-
|
|
12244
|
-
|
|
12245
|
-
|
|
12246
|
-
|
|
12247
|
-
|
|
12248
|
-
|
|
12249
|
-
|
|
12250
|
-
|
|
12251
|
-
|
|
12252
|
-
|
|
12253
|
-
|
|
12254
|
-
|
|
12255
|
-
|
|
12256
|
-
|
|
12257
|
-
|
|
12258
|
-
|
|
12259
|
-
|
|
12260
|
-
|
|
12261
|
-
|
|
12262
|
-
|
|
12419
|
+
) }) : null
|
|
12420
|
+
] }) }),
|
|
12421
|
+
/* @__PURE__ */ jsx(
|
|
12422
|
+
"div",
|
|
12423
|
+
{
|
|
12424
|
+
class: "mt-2",
|
|
12425
|
+
id: "version-list",
|
|
12426
|
+
"hx-get": `/web/libraries/${encodeURIComponent(library.name)}/versions-list`,
|
|
12427
|
+
"hx-trigger": "library-change from:body",
|
|
12428
|
+
"hx-swap": "morph:innerHTML",
|
|
12429
|
+
children: versions.length > 0 ? versions.map((v) => {
|
|
12430
|
+
const adapted = {
|
|
12431
|
+
id: -1,
|
|
12432
|
+
ref: { library: library.name, version: v.version },
|
|
12433
|
+
status: v.status,
|
|
12434
|
+
progress: v.progress,
|
|
12435
|
+
counts: {
|
|
12436
|
+
documents: v.documentCount,
|
|
12437
|
+
uniqueUrls: v.uniqueUrlCount
|
|
12438
|
+
},
|
|
12439
|
+
indexedAt: v.indexedAt,
|
|
12440
|
+
sourceUrl: v.sourceUrl ?? void 0
|
|
12441
|
+
};
|
|
12442
|
+
return /* @__PURE__ */ jsx(
|
|
12443
|
+
VersionDetailsRow,
|
|
12444
|
+
{
|
|
12445
|
+
libraryName: library.name,
|
|
12446
|
+
version: adapted,
|
|
12447
|
+
showDelete: true,
|
|
12448
|
+
showRefresh: true
|
|
12449
|
+
}
|
|
12450
|
+
);
|
|
12451
|
+
}) : /* @__PURE__ */ jsx("p", { class: "text-sm text-gray-500 dark:text-gray-400 italic", children: "No versions indexed." })
|
|
12452
|
+
}
|
|
12453
|
+
),
|
|
12454
|
+
/* @__PURE__ */ jsx("div", { id: "add-version-form-container", class: "mt-4", children: /* @__PURE__ */ jsx(AddVersionButton, { libraryName: library.name }) })
|
|
12455
|
+
] });
|
|
12263
12456
|
};
|
|
12264
12457
|
const LibrarySearchCard = ({ library }) => {
|
|
12265
12458
|
return /* @__PURE__ */ jsxs("div", { class: "block p-4 bg-white dark:bg-gray-800 rounded-lg shadow-sm border border-gray-300 dark:border-gray-600 mb-4", children: [
|
|
@@ -12285,7 +12478,7 @@ const LibrarySearchCard = ({ library }) => {
|
|
|
12285
12478
|
children: [
|
|
12286
12479
|
/* @__PURE__ */ jsx("option", { value: "", children: "Latest" }),
|
|
12287
12480
|
" ",
|
|
12288
|
-
library.versions.map((version) => /* @__PURE__ */ jsx("option", { value: version.version || "
|
|
12481
|
+
library.versions.map((version) => /* @__PURE__ */ jsx("option", { value: version.version || "latest", safe: true, children: version.version || "Latest" }))
|
|
12289
12482
|
]
|
|
12290
12483
|
}
|
|
12291
12484
|
),
|
|
@@ -12359,7 +12552,7 @@ const SearchResultSkeletonItem = () => /* @__PURE__ */ jsxs("div", { class: "blo
|
|
|
12359
12552
|
/* @__PURE__ */ jsx("div", { class: "h-[0.8em] bg-gray-200 dark:bg-gray-700 rounded w-full mb-2" }),
|
|
12360
12553
|
/* @__PURE__ */ jsx("div", { class: "h-[0.8em] bg-gray-200 dark:bg-gray-700 rounded w-5/6" })
|
|
12361
12554
|
] });
|
|
12362
|
-
function registerLibraryDetailRoutes(server, listLibrariesTool, searchTool) {
|
|
12555
|
+
function registerLibraryDetailRoutes(server, listLibrariesTool, searchTool, scrapeTool, docService) {
|
|
12363
12556
|
server.get(
|
|
12364
12557
|
"/libraries/:libraryName",
|
|
12365
12558
|
async (request, reply) => {
|
|
@@ -12367,7 +12560,7 @@ function registerLibraryDetailRoutes(server, listLibrariesTool, searchTool) {
|
|
|
12367
12560
|
try {
|
|
12368
12561
|
const result = await listLibrariesTool.execute();
|
|
12369
12562
|
const libraryInfo = result.libraries.find(
|
|
12370
|
-
(lib) => lib.name === libraryName
|
|
12563
|
+
(lib) => lib.name.toLowerCase() === libraryName.toLowerCase()
|
|
12371
12564
|
);
|
|
12372
12565
|
if (!libraryInfo) {
|
|
12373
12566
|
reply.status(404).send("Library not found");
|
|
@@ -12404,7 +12597,7 @@ function registerLibraryDetailRoutes(server, listLibrariesTool, searchTool) {
|
|
|
12404
12597
|
reply.status(400).send("Search query is required.");
|
|
12405
12598
|
return;
|
|
12406
12599
|
}
|
|
12407
|
-
const versionParam = version === "
|
|
12600
|
+
const versionParam = version === "latest" ? void 0 : version;
|
|
12408
12601
|
try {
|
|
12409
12602
|
const searchResult = await searchTool.execute({
|
|
12410
12603
|
library: libraryName,
|
|
@@ -12423,9 +12616,128 @@ function registerLibraryDetailRoutes(server, listLibrariesTool, searchTool) {
|
|
|
12423
12616
|
}
|
|
12424
12617
|
}
|
|
12425
12618
|
);
|
|
12619
|
+
server.get(
|
|
12620
|
+
"/web/libraries/:libraryName/versions-list",
|
|
12621
|
+
async (request, reply) => {
|
|
12622
|
+
const { libraryName } = request.params;
|
|
12623
|
+
try {
|
|
12624
|
+
const result = await listLibrariesTool.execute();
|
|
12625
|
+
const libraryInfo = result.libraries.find(
|
|
12626
|
+
(lib) => lib.name.toLowerCase() === libraryName.toLowerCase()
|
|
12627
|
+
);
|
|
12628
|
+
if (!libraryInfo) {
|
|
12629
|
+
reply.status(404).send("Library not found");
|
|
12630
|
+
return;
|
|
12631
|
+
}
|
|
12632
|
+
const versions = libraryInfo.versions || [];
|
|
12633
|
+
reply.type("text/html; charset=utf-8");
|
|
12634
|
+
if (versions.length === 0) {
|
|
12635
|
+
return /* @__PURE__ */ jsx("p", { class: "text-sm text-gray-500 dark:text-gray-400 italic", children: "No versions indexed." });
|
|
12636
|
+
}
|
|
12637
|
+
return /* @__PURE__ */ jsx(Fragment, { children: versions.map((v) => {
|
|
12638
|
+
const adapted = {
|
|
12639
|
+
id: -1,
|
|
12640
|
+
ref: { library: libraryInfo.name, version: v.version },
|
|
12641
|
+
status: v.status,
|
|
12642
|
+
progress: v.progress,
|
|
12643
|
+
counts: {
|
|
12644
|
+
documents: v.documentCount,
|
|
12645
|
+
uniqueUrls: v.uniqueUrlCount
|
|
12646
|
+
},
|
|
12647
|
+
indexedAt: v.indexedAt,
|
|
12648
|
+
sourceUrl: v.sourceUrl ?? void 0
|
|
12649
|
+
};
|
|
12650
|
+
return /* @__PURE__ */ jsx(
|
|
12651
|
+
VersionDetailsRow,
|
|
12652
|
+
{
|
|
12653
|
+
libraryName: libraryInfo.name,
|
|
12654
|
+
version: adapted,
|
|
12655
|
+
showDelete: true,
|
|
12656
|
+
showRefresh: true
|
|
12657
|
+
}
|
|
12658
|
+
);
|
|
12659
|
+
}) });
|
|
12660
|
+
} catch (error) {
|
|
12661
|
+
logger.error(`Failed to fetch versions for ${libraryName}: ${error}`);
|
|
12662
|
+
reply.status(500).send("Internal Server Error");
|
|
12663
|
+
}
|
|
12664
|
+
}
|
|
12665
|
+
);
|
|
12666
|
+
server.get(
|
|
12667
|
+
"/web/libraries/:libraryName/add-version-button",
|
|
12668
|
+
async (request, reply) => {
|
|
12669
|
+
const { libraryName } = request.params;
|
|
12670
|
+
reply.type("text/html; charset=utf-8");
|
|
12671
|
+
return /* @__PURE__ */ jsx(AddVersionButton, { libraryName });
|
|
12672
|
+
}
|
|
12673
|
+
);
|
|
12674
|
+
server.get(
|
|
12675
|
+
"/web/libraries/:libraryName/add-version-form",
|
|
12676
|
+
async (request, reply) => {
|
|
12677
|
+
const { libraryName } = request.params;
|
|
12678
|
+
try {
|
|
12679
|
+
const result = await listLibrariesTool.execute();
|
|
12680
|
+
const libraryInfo = result.libraries.find(
|
|
12681
|
+
(lib) => lib.name.toLowerCase() === libraryName.toLowerCase()
|
|
12682
|
+
);
|
|
12683
|
+
if (!libraryInfo) {
|
|
12684
|
+
reply.status(404).send("Library not found");
|
|
12685
|
+
return;
|
|
12686
|
+
}
|
|
12687
|
+
const versions = libraryInfo.versions || [];
|
|
12688
|
+
const latestVersion = versions[0];
|
|
12689
|
+
let initialValues = {
|
|
12690
|
+
library: libraryName
|
|
12691
|
+
};
|
|
12692
|
+
if (latestVersion) {
|
|
12693
|
+
const summaries = await docService.listLibraries();
|
|
12694
|
+
const libSummary = summaries.find(
|
|
12695
|
+
(s) => s.library.toLowerCase() === libraryName.toLowerCase()
|
|
12696
|
+
);
|
|
12697
|
+
if (libSummary) {
|
|
12698
|
+
const versionSummary = libSummary.versions.find(
|
|
12699
|
+
(v) => v.ref.version === (latestVersion.version || "") || !latestVersion.version && v.ref.version === ""
|
|
12700
|
+
);
|
|
12701
|
+
if (versionSummary) {
|
|
12702
|
+
const scraperConfig = await docService.getScraperOptions(
|
|
12703
|
+
versionSummary.id
|
|
12704
|
+
);
|
|
12705
|
+
if (scraperConfig) {
|
|
12706
|
+
const opts = scraperConfig.options;
|
|
12707
|
+
initialValues = {
|
|
12708
|
+
library: libraryName,
|
|
12709
|
+
url: scraperConfig.sourceUrl,
|
|
12710
|
+
maxPages: opts.maxPages,
|
|
12711
|
+
maxDepth: opts.maxDepth,
|
|
12712
|
+
scope: opts.scope,
|
|
12713
|
+
includePatterns: opts.includePatterns?.join("\n"),
|
|
12714
|
+
excludePatterns: opts.excludePatterns?.join("\n"),
|
|
12715
|
+
scrapeMode: opts.scrapeMode,
|
|
12716
|
+
headers: opts.headers ? Object.entries(opts.headers).map(([name, value]) => ({
|
|
12717
|
+
name,
|
|
12718
|
+
value
|
|
12719
|
+
})) : void 0,
|
|
12720
|
+
followRedirects: opts.followRedirects,
|
|
12721
|
+
ignoreErrors: opts.ignoreErrors
|
|
12722
|
+
};
|
|
12723
|
+
}
|
|
12724
|
+
}
|
|
12725
|
+
}
|
|
12726
|
+
}
|
|
12727
|
+
reply.type("text/html; charset=utf-8");
|
|
12728
|
+
return /* @__PURE__ */ jsx(ScrapeFormContent, { initialValues, mode: "add-version" });
|
|
12729
|
+
} catch (error) {
|
|
12730
|
+
logger.error(
|
|
12731
|
+
`Failed to load add-version form for ${libraryName}: ${error}`
|
|
12732
|
+
);
|
|
12733
|
+
reply.type("text/html; charset=utf-8");
|
|
12734
|
+
return /* @__PURE__ */ jsx(Alert, { type: "error", message: "Failed to load the add version form." });
|
|
12735
|
+
}
|
|
12736
|
+
}
|
|
12737
|
+
);
|
|
12426
12738
|
}
|
|
12427
12739
|
const LibraryItem = ({ library }) => {
|
|
12428
|
-
const versions = library.versions
|
|
12740
|
+
const versions = library.versions || [];
|
|
12429
12741
|
const latestVersion = versions[0];
|
|
12430
12742
|
return (
|
|
12431
12743
|
// Use Flowbite Card structure with updated padding and border, and white background
|
|
@@ -12514,7 +12826,7 @@ const LibraryList = ({ libraries }) => {
|
|
|
12514
12826
|
}
|
|
12515
12827
|
);
|
|
12516
12828
|
};
|
|
12517
|
-
function registerLibrariesRoutes(server, listLibrariesTool, removeTool) {
|
|
12829
|
+
function registerLibrariesRoutes(server, listLibrariesTool, removeTool, refreshVersionTool) {
|
|
12518
12830
|
server.get("/web/libraries", async (_request, reply) => {
|
|
12519
12831
|
try {
|
|
12520
12832
|
const result = await listLibrariesTool.execute();
|
|
@@ -12529,9 +12841,16 @@ function registerLibrariesRoutes(server, listLibrariesTool, removeTool) {
|
|
|
12529
12841
|
"/web/libraries/:libraryName/versions/:versionParam",
|
|
12530
12842
|
async (request, reply) => {
|
|
12531
12843
|
const { libraryName, versionParam } = request.params;
|
|
12532
|
-
const version = versionParam === "
|
|
12844
|
+
const version = versionParam === "latest" ? void 0 : versionParam;
|
|
12533
12845
|
try {
|
|
12534
12846
|
await removeTool.execute({ library: libraryName, version });
|
|
12847
|
+
const result = await listLibrariesTool.execute();
|
|
12848
|
+
const libraryStillExists = result.libraries.some(
|
|
12849
|
+
(lib) => lib.name.toLowerCase() === libraryName.toLowerCase()
|
|
12850
|
+
);
|
|
12851
|
+
if (!libraryStillExists) {
|
|
12852
|
+
reply.header("HX-Redirect", "/");
|
|
12853
|
+
}
|
|
12535
12854
|
reply.status(204).send();
|
|
12536
12855
|
} catch (error) {
|
|
12537
12856
|
logger.error(
|
|
@@ -12541,6 +12860,46 @@ function registerLibrariesRoutes(server, listLibrariesTool, removeTool) {
|
|
|
12541
12860
|
}
|
|
12542
12861
|
}
|
|
12543
12862
|
);
|
|
12863
|
+
server.post(
|
|
12864
|
+
"/web/libraries/:libraryName/versions/:versionParam/refresh",
|
|
12865
|
+
async (request, reply) => {
|
|
12866
|
+
const { libraryName, versionParam } = request.params;
|
|
12867
|
+
const version = versionParam === "latest" || versionParam === "" ? void 0 : versionParam;
|
|
12868
|
+
try {
|
|
12869
|
+
await refreshVersionTool.execute({
|
|
12870
|
+
library: libraryName,
|
|
12871
|
+
version,
|
|
12872
|
+
waitForCompletion: false
|
|
12873
|
+
});
|
|
12874
|
+
const versionDisplay = version || "latest";
|
|
12875
|
+
reply.header(
|
|
12876
|
+
"HX-Trigger",
|
|
12877
|
+
JSON.stringify({
|
|
12878
|
+
toast: {
|
|
12879
|
+
message: `Refresh started for ${libraryName}@${versionDisplay}`,
|
|
12880
|
+
type: "success"
|
|
12881
|
+
}
|
|
12882
|
+
})
|
|
12883
|
+
);
|
|
12884
|
+
reply.status(204).send();
|
|
12885
|
+
} catch (error) {
|
|
12886
|
+
logger.error(
|
|
12887
|
+
`Failed to refresh ${libraryName}@${versionParam}: ${error}`
|
|
12888
|
+
);
|
|
12889
|
+
const errorMessage = error instanceof Error ? error.message : "Failed to refresh version.";
|
|
12890
|
+
reply.header(
|
|
12891
|
+
"HX-Trigger",
|
|
12892
|
+
JSON.stringify({
|
|
12893
|
+
toast: {
|
|
12894
|
+
message: errorMessage,
|
|
12895
|
+
type: "error"
|
|
12896
|
+
}
|
|
12897
|
+
})
|
|
12898
|
+
);
|
|
12899
|
+
reply.status(500).send();
|
|
12900
|
+
}
|
|
12901
|
+
}
|
|
12902
|
+
);
|
|
12544
12903
|
}
|
|
12545
12904
|
function formatNumber(num) {
|
|
12546
12905
|
if (num >= 1e9) {
|
|
@@ -12616,12 +12975,19 @@ async function registerWebService(server, docService, pipeline, eventBus, config
|
|
|
12616
12975
|
const listJobsTool = new ListJobsTool(pipeline);
|
|
12617
12976
|
const scrapeTool = new ScrapeTool(pipeline);
|
|
12618
12977
|
const removeTool = new RemoveTool(docService, pipeline);
|
|
12978
|
+
const refreshVersionTool = new RefreshVersionTool(pipeline);
|
|
12619
12979
|
const searchTool = new SearchTool(docService);
|
|
12620
12980
|
const cancelJobTool = new CancelJobTool(pipeline);
|
|
12621
12981
|
const clearCompletedJobsTool = new ClearCompletedJobsTool(pipeline);
|
|
12622
12982
|
registerIndexRoute(server, config);
|
|
12623
|
-
registerLibrariesRoutes(server, listLibrariesTool, removeTool);
|
|
12624
|
-
registerLibraryDetailRoutes(
|
|
12983
|
+
registerLibrariesRoutes(server, listLibrariesTool, removeTool, refreshVersionTool);
|
|
12984
|
+
registerLibraryDetailRoutes(
|
|
12985
|
+
server,
|
|
12986
|
+
listLibrariesTool,
|
|
12987
|
+
searchTool,
|
|
12988
|
+
scrapeTool,
|
|
12989
|
+
docService
|
|
12990
|
+
);
|
|
12625
12991
|
registerJobListRoutes(server, listJobsTool);
|
|
12626
12992
|
registerNewJobRoutes(server, scrapeTool);
|
|
12627
12993
|
registerCancelJobRoute(server, cancelJobTool);
|
|
@@ -12683,7 +13049,7 @@ class AppServer {
|
|
|
12683
13049
|
try {
|
|
12684
13050
|
if (telemetry.isEnabled()) {
|
|
12685
13051
|
telemetry.setGlobalContext({
|
|
12686
|
-
appVersion: "1.
|
|
13052
|
+
appVersion: "1.31.1",
|
|
12687
13053
|
appPlatform: process.platform,
|
|
12688
13054
|
appNodeVersion: process.version,
|
|
12689
13055
|
appServicesEnabled: this.getActiveServicesList(),
|
|
@@ -14347,11 +14713,11 @@ class PipelineWorker {
|
|
|
14347
14713
|
if (!scraperOptions.isRefresh) {
|
|
14348
14714
|
await this.store.removeAllDocuments(library, version);
|
|
14349
14715
|
logger.info(
|
|
14350
|
-
`💾 Cleared store for ${library}@${version || "
|
|
14716
|
+
`💾 Cleared store for ${library}@${version || "latest"} before scraping.`
|
|
14351
14717
|
);
|
|
14352
14718
|
} else {
|
|
14353
14719
|
logger.info(
|
|
14354
|
-
`🔄 Refresh operation - preserving existing data for ${library}@${version || "
|
|
14720
|
+
`🔄 Refresh operation - preserving existing data for ${library}@${version || "latest"}.`
|
|
14355
14721
|
);
|
|
14356
14722
|
}
|
|
14357
14723
|
await this.scraperService.scrape(
|
|
@@ -14503,7 +14869,7 @@ class PipelineManager {
|
|
|
14503
14869
|
for (const version of runningVersions) {
|
|
14504
14870
|
await this.store.updateVersionStatus(version.id, VersionStatus.QUEUED);
|
|
14505
14871
|
logger.info(
|
|
14506
|
-
`🔄 Reset interrupted job to QUEUED: ${version.library_name}@${version.name || "
|
|
14872
|
+
`🔄 Reset interrupted job to QUEUED: ${version.library_name}@${version.name || "latest"}`
|
|
14507
14873
|
);
|
|
14508
14874
|
}
|
|
14509
14875
|
const queuedVersions = await this.store.getVersionsByStatus([VersionStatus.QUEUED]);
|
|
@@ -14524,7 +14890,7 @@ class PipelineManager {
|
|
|
14524
14890
|
parsedScraperOptions = JSON.parse(version.scraper_options);
|
|
14525
14891
|
} catch (error) {
|
|
14526
14892
|
logger.warn(
|
|
14527
|
-
`⚠️ Failed to parse scraper options for ${version.library_name}@${version.name || "
|
|
14893
|
+
`⚠️ Failed to parse scraper options for ${version.library_name}@${version.name || "latest"}: ${error}`
|
|
14528
14894
|
);
|
|
14529
14895
|
}
|
|
14530
14896
|
}
|
|
@@ -14631,7 +14997,7 @@ class PipelineManager {
|
|
|
14631
14997
|
this.jobMap.set(jobId, job);
|
|
14632
14998
|
this.jobQueue.push(jobId);
|
|
14633
14999
|
logger.info(
|
|
14634
|
-
`📝 Job enqueued: ${jobId} for ${library}${normalizedVersion ? `@${normalizedVersion}` : " (
|
|
15000
|
+
`📝 Job enqueued: ${jobId} for ${library}${normalizedVersion ? `@${normalizedVersion}` : " (latest)"}`
|
|
14635
15001
|
);
|
|
14636
15002
|
await this.updateJobStatus(job, PipelineJobStatus.QUEUED);
|
|
14637
15003
|
if (this.isRunning) {
|
|
@@ -14665,7 +15031,7 @@ class PipelineManager {
|
|
|
14665
15031
|
}
|
|
14666
15032
|
if (versionInfo && versionInfo.status !== VersionStatus.COMPLETED) {
|
|
14667
15033
|
logger.info(
|
|
14668
|
-
`⚠️ Version ${library}@${normalizedVersion || "
|
|
15034
|
+
`⚠️ Version ${library}@${normalizedVersion || "latest"} has status "${versionInfo.status}". Performing full re-scrape instead of refresh.`
|
|
14669
15035
|
);
|
|
14670
15036
|
return this.enqueueJobWithStoredOptions(library, normalizedVersion);
|
|
14671
15037
|
}
|
|
@@ -14677,11 +15043,11 @@ class PipelineManager {
|
|
|
14677
15043
|
}
|
|
14678
15044
|
if (pages.length === 0) {
|
|
14679
15045
|
throw new Error(
|
|
14680
|
-
`No pages found for ${library}@${normalizedVersion || "
|
|
15046
|
+
`No pages found for ${library}@${normalizedVersion || "latest"}. Use scrape_docs to index it first.`
|
|
14681
15047
|
);
|
|
14682
15048
|
}
|
|
14683
15049
|
logger.info(
|
|
14684
|
-
`🔄 Preparing refresh job for ${library}@${normalizedVersion || "
|
|
15050
|
+
`🔄 Preparing refresh job for ${library}@${normalizedVersion || "latest"} with ${pages.length} page(s)`
|
|
14685
15051
|
);
|
|
14686
15052
|
const initialQueue = pages.map((page) => ({
|
|
14687
15053
|
url: page.url,
|
|
@@ -14705,7 +15071,7 @@ class PipelineManager {
|
|
|
14705
15071
|
// Mark this as a refresh operation
|
|
14706
15072
|
};
|
|
14707
15073
|
logger.info(
|
|
14708
|
-
`📝 Enqueueing refresh job for ${library}@${normalizedVersion || "
|
|
15074
|
+
`📝 Enqueueing refresh job for ${library}@${normalizedVersion || "latest"}`
|
|
14709
15075
|
);
|
|
14710
15076
|
return this.enqueueScrapeJob(library, normalizedVersion, scraperOptions);
|
|
14711
15077
|
} catch (error) {
|
|
@@ -14727,7 +15093,7 @@ class PipelineManager {
|
|
|
14727
15093
|
const stored = await this.store.getScraperOptions(versionId);
|
|
14728
15094
|
if (!stored) {
|
|
14729
15095
|
throw new Error(
|
|
14730
|
-
`No stored scraper options found for ${library}@${normalizedVersion || "
|
|
15096
|
+
`No stored scraper options found for ${library}@${normalizedVersion || "latest"}`
|
|
14731
15097
|
);
|
|
14732
15098
|
}
|
|
14733
15099
|
const storedOptions = stored.options;
|
|
@@ -14738,7 +15104,7 @@ class PipelineManager {
|
|
|
14738
15104
|
...storedOptions
|
|
14739
15105
|
};
|
|
14740
15106
|
logger.info(
|
|
14741
|
-
`🔄 Re-indexing ${library}@${normalizedVersion || "
|
|
15107
|
+
`🔄 Re-indexing ${library}@${normalizedVersion || "latest"} with stored options from ${stored.sourceUrl}`
|
|
14742
15108
|
);
|
|
14743
15109
|
return this.enqueueScrapeJob(library, normalizedVersion, completeOptions);
|
|
14744
15110
|
} catch (error) {
|
|
@@ -15774,7 +16140,7 @@ async function removeAction(library, options, command) {
|
|
|
15774
16140
|
function createRemoveCommand(program) {
|
|
15775
16141
|
return program.command("remove <library>").description("Remove documents for a specific library and version").option(
|
|
15776
16142
|
"-v, --version <string>",
|
|
15777
|
-
"Version to remove (optional, removes
|
|
16143
|
+
"Version to remove (optional, removes latest if omitted)"
|
|
15778
16144
|
).option(
|
|
15779
16145
|
"--server-url <url>",
|
|
15780
16146
|
"URL of external pipeline worker RPC (e.g., http://localhost:8080/api)"
|
|
@@ -16170,7 +16536,7 @@ function createCliProgram() {
|
|
|
16170
16536
|
const commandStartTimes = /* @__PURE__ */ new Map();
|
|
16171
16537
|
let globalEventBus = null;
|
|
16172
16538
|
let globalTelemetryService = null;
|
|
16173
|
-
program.name("docs-mcp-server").description("Unified CLI, MCP Server, and Web Interface for Docs MCP Server.").version("1.
|
|
16539
|
+
program.name("docs-mcp-server").description("Unified CLI, MCP Server, and Web Interface for Docs MCP Server.").version("1.31.1").addOption(
|
|
16174
16540
|
new Option("--verbose", "Enable verbose (debug) logging").conflicts("silent")
|
|
16175
16541
|
).addOption(new Option("--silent", "Disable all logging except errors")).addOption(
|
|
16176
16542
|
new Option("--telemetry", "Enable telemetry collection").env("DOCS_MCP_TELEMETRY").argParser((value) => {
|
|
@@ -16204,7 +16570,7 @@ function createCliProgram() {
|
|
|
16204
16570
|
if (shouldEnableTelemetry()) {
|
|
16205
16571
|
if (telemetry.isEnabled()) {
|
|
16206
16572
|
telemetry.setGlobalContext({
|
|
16207
|
-
appVersion: "1.
|
|
16573
|
+
appVersion: "1.31.1",
|
|
16208
16574
|
appPlatform: process.platform,
|
|
16209
16575
|
appNodeVersion: process.version,
|
|
16210
16576
|
appInterface: "cli",
|