@seo-console/package 1.1.2 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +103 -1
- package/dist/index.d.mts +2 -79
- package/dist/index.d.ts +2 -79
- package/dist/index.js +0 -230
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +0 -224
- package/dist/index.mjs.map +1 -1
- package/dist/server.d.mts +80 -3
- package/dist/server.d.ts +80 -3
- package/dist/server.js +12858 -0
- package/dist/server.js.map +1 -1
- package/dist/server.mjs +12869 -0
- package/dist/server.mjs.map +1 -1
- package/dist/{robots-generator-CYA9Ofu_.d.ts → storage-factory-CdCI1VHl.d.mts} +54 -23
- package/dist/{robots-generator-9d9aTULk.d.mts → storage-factory-L2YGjVID.d.ts} +54 -23
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -3578,82 +3578,6 @@ function ValidationDashboard() {
|
|
|
3578
3578
|
] });
|
|
3579
3579
|
}
|
|
3580
3580
|
|
|
3581
|
-
// src/lib/route-discovery.ts
|
|
3582
|
-
import { join } from "path";
|
|
3583
|
-
import { glob } from "glob";
|
|
3584
|
-
async function discoverNextJSRoutes(appDir = "app", rootDir = process.cwd()) {
|
|
3585
|
-
const routes = [];
|
|
3586
|
-
const appPath = join(rootDir, appDir);
|
|
3587
|
-
try {
|
|
3588
|
-
const pageFiles = await glob("**/page.tsx", {
|
|
3589
|
-
cwd: appPath,
|
|
3590
|
-
absolute: false,
|
|
3591
|
-
ignore: ["**/node_modules/**", "**/.next/**"]
|
|
3592
|
-
});
|
|
3593
|
-
for (const file of pageFiles) {
|
|
3594
|
-
const route = fileToRoute(file, appDir);
|
|
3595
|
-
if (route) {
|
|
3596
|
-
routes.push(route);
|
|
3597
|
-
}
|
|
3598
|
-
}
|
|
3599
|
-
} catch (error) {
|
|
3600
|
-
console.error("Error discovering routes:", error);
|
|
3601
|
-
}
|
|
3602
|
-
return routes;
|
|
3603
|
-
}
|
|
3604
|
-
function fileToRoute(filePath, appDir) {
|
|
3605
|
-
let routePath = filePath.replace(/^app\//, "").replace(/\/page\.tsx$/, "").replace(/\/page$/, "");
|
|
3606
|
-
if (routePath === "page" || routePath === "") {
|
|
3607
|
-
routePath = "/";
|
|
3608
|
-
} else {
|
|
3609
|
-
routePath = "/" + routePath;
|
|
3610
|
-
}
|
|
3611
|
-
const segments = routePath.split("/").filter(Boolean);
|
|
3612
|
-
const params = [];
|
|
3613
|
-
let isDynamic = false;
|
|
3614
|
-
let isCatchAll = false;
|
|
3615
|
-
for (const segment of segments) {
|
|
3616
|
-
if (segment.startsWith("[...") && segment.endsWith("]")) {
|
|
3617
|
-
const param = segment.slice(4, -1);
|
|
3618
|
-
params.push(param);
|
|
3619
|
-
isDynamic = true;
|
|
3620
|
-
isCatchAll = true;
|
|
3621
|
-
} else if (segment.startsWith("[") && segment.endsWith("]")) {
|
|
3622
|
-
const param = segment.slice(1, -1);
|
|
3623
|
-
params.push(param);
|
|
3624
|
-
isDynamic = true;
|
|
3625
|
-
}
|
|
3626
|
-
}
|
|
3627
|
-
return {
|
|
3628
|
-
routePath,
|
|
3629
|
-
filePath: join(appDir, filePath),
|
|
3630
|
-
isDynamic,
|
|
3631
|
-
isCatchAll,
|
|
3632
|
-
params
|
|
3633
|
-
};
|
|
3634
|
-
}
|
|
3635
|
-
function generateExamplePaths(route, count = 3) {
|
|
3636
|
-
if (!route.isDynamic) {
|
|
3637
|
-
return [route.routePath];
|
|
3638
|
-
}
|
|
3639
|
-
const examples = [];
|
|
3640
|
-
const segments = route.routePath.split("/").filter(Boolean);
|
|
3641
|
-
for (let i = 0; i < count; i++) {
|
|
3642
|
-
let examplePath = "";
|
|
3643
|
-
for (const segment of segments) {
|
|
3644
|
-
if (segment.startsWith("[...")) {
|
|
3645
|
-
examplePath += `/example-${i}-part-1/example-${i}-part-2`;
|
|
3646
|
-
} else if (segment.startsWith("[")) {
|
|
3647
|
-
examplePath += `/example-${i}`;
|
|
3648
|
-
} else {
|
|
3649
|
-
examplePath += `/${segment}`;
|
|
3650
|
-
}
|
|
3651
|
-
}
|
|
3652
|
-
examples.push(examplePath || "/");
|
|
3653
|
-
}
|
|
3654
|
-
return examples;
|
|
3655
|
-
}
|
|
3656
|
-
|
|
3657
3581
|
// src/lib/metadata-extractor.ts
|
|
3658
3582
|
import * as cheerio from "cheerio";
|
|
3659
3583
|
function extractMetadataFromHTML(html, baseUrl) {
|
|
@@ -3682,23 +3606,6 @@ function extractMetadataFromHTML(html, baseUrl) {
|
|
|
3682
3606
|
}
|
|
3683
3607
|
return metadata;
|
|
3684
3608
|
}
|
|
3685
|
-
async function extractMetadataFromURL(url) {
|
|
3686
|
-
try {
|
|
3687
|
-
const response = await fetch(url, {
|
|
3688
|
-
headers: {
|
|
3689
|
-
"User-Agent": "SEO-Console/1.0"
|
|
3690
|
-
}
|
|
3691
|
-
});
|
|
3692
|
-
if (!response.ok) {
|
|
3693
|
-
throw new Error(`Failed to fetch ${url}: ${response.statusText}`);
|
|
3694
|
-
}
|
|
3695
|
-
const html = await response.text();
|
|
3696
|
-
return extractMetadataFromHTML(html, url);
|
|
3697
|
-
} catch (error) {
|
|
3698
|
-
console.error(`Error extracting metadata from ${url}:`, error);
|
|
3699
|
-
return {};
|
|
3700
|
-
}
|
|
3701
|
-
}
|
|
3702
3609
|
function metadataToSEORecord(metadata, routePath, userId = "extracted") {
|
|
3703
3610
|
return {
|
|
3704
3611
|
userId,
|
|
@@ -3716,20 +3623,6 @@ function metadataToSEORecord(metadata, routePath, userId = "extracted") {
|
|
|
3716
3623
|
validationStatus: "pending"
|
|
3717
3624
|
};
|
|
3718
3625
|
}
|
|
3719
|
-
async function crawlSiteForSEO(baseUrl, routes) {
|
|
3720
|
-
const results = /* @__PURE__ */ new Map();
|
|
3721
|
-
for (const route of routes) {
|
|
3722
|
-
const url = new URL(route, baseUrl).toString();
|
|
3723
|
-
try {
|
|
3724
|
-
const metadata = await extractMetadataFromURL(url);
|
|
3725
|
-
results.set(route, metadata);
|
|
3726
|
-
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
3727
|
-
} catch (error) {
|
|
3728
|
-
console.error(`Failed to crawl ${url}:`, error);
|
|
3729
|
-
}
|
|
3730
|
-
}
|
|
3731
|
-
return results;
|
|
3732
|
-
}
|
|
3733
3626
|
|
|
3734
3627
|
// src/lib/sitemap-generator.ts
|
|
3735
3628
|
function generateSitemapXML(options) {
|
|
@@ -3871,119 +3764,8 @@ function extractSitemapFromRobotsTxt(content) {
|
|
|
3871
3764
|
|
|
3872
3765
|
// src/lib/storage/file-storage.ts
|
|
3873
3766
|
import { promises as fs } from "fs";
|
|
3874
|
-
var FileStorage = class {
|
|
3875
|
-
constructor(filePath = "seo-records.json") {
|
|
3876
|
-
this.records = [];
|
|
3877
|
-
this.initialized = false;
|
|
3878
|
-
this.filePath = filePath;
|
|
3879
|
-
}
|
|
3880
|
-
async ensureInitialized() {
|
|
3881
|
-
if (this.initialized) return;
|
|
3882
|
-
try {
|
|
3883
|
-
const data = await fs.readFile(this.filePath, "utf-8");
|
|
3884
|
-
this.records = JSON.parse(data);
|
|
3885
|
-
} catch (error) {
|
|
3886
|
-
if (error.code === "ENOENT") {
|
|
3887
|
-
this.records = [];
|
|
3888
|
-
await this.save();
|
|
3889
|
-
} else {
|
|
3890
|
-
throw error;
|
|
3891
|
-
}
|
|
3892
|
-
}
|
|
3893
|
-
this.initialized = true;
|
|
3894
|
-
}
|
|
3895
|
-
async save() {
|
|
3896
|
-
await fs.writeFile(this.filePath, JSON.stringify(this.records, null, 2), "utf-8");
|
|
3897
|
-
}
|
|
3898
|
-
async isAvailable() {
|
|
3899
|
-
try {
|
|
3900
|
-
const dir = this.filePath.includes("/") ? this.filePath.substring(0, this.filePath.lastIndexOf("/")) : ".";
|
|
3901
|
-
await fs.access(dir);
|
|
3902
|
-
return true;
|
|
3903
|
-
} catch {
|
|
3904
|
-
return false;
|
|
3905
|
-
}
|
|
3906
|
-
}
|
|
3907
|
-
async getRecords() {
|
|
3908
|
-
await this.ensureInitialized();
|
|
3909
|
-
return [...this.records];
|
|
3910
|
-
}
|
|
3911
|
-
async getRecordById(id) {
|
|
3912
|
-
await this.ensureInitialized();
|
|
3913
|
-
return this.records.find((r) => r.id === id) || null;
|
|
3914
|
-
}
|
|
3915
|
-
async getRecordByRoute(routePath) {
|
|
3916
|
-
await this.ensureInitialized();
|
|
3917
|
-
return this.records.find((r) => r.routePath === routePath) || null;
|
|
3918
|
-
}
|
|
3919
|
-
async createRecord(record) {
|
|
3920
|
-
await this.ensureInitialized();
|
|
3921
|
-
const newRecord = {
|
|
3922
|
-
id: typeof crypto !== "undefined" && crypto.randomUUID ? crypto.randomUUID() : `${Date.now()}-${Math.random().toString(36).substring(2, 9)}`,
|
|
3923
|
-
userId: "file-user",
|
|
3924
|
-
// File storage doesn't need user IDs
|
|
3925
|
-
routePath: record.routePath,
|
|
3926
|
-
title: record.title,
|
|
3927
|
-
description: record.description,
|
|
3928
|
-
keywords: record.keywords,
|
|
3929
|
-
ogTitle: record.ogTitle,
|
|
3930
|
-
ogDescription: record.ogDescription,
|
|
3931
|
-
ogImageUrl: record.ogImageUrl,
|
|
3932
|
-
ogImageWidth: record.ogImageWidth,
|
|
3933
|
-
ogImageHeight: record.ogImageHeight,
|
|
3934
|
-
ogType: record.ogType,
|
|
3935
|
-
ogUrl: record.ogUrl,
|
|
3936
|
-
ogSiteName: record.ogSiteName,
|
|
3937
|
-
twitterCard: record.twitterCard,
|
|
3938
|
-
twitterTitle: record.twitterTitle,
|
|
3939
|
-
twitterDescription: record.twitterDescription,
|
|
3940
|
-
twitterImageUrl: record.twitterImageUrl,
|
|
3941
|
-
twitterSite: record.twitterSite,
|
|
3942
|
-
twitterCreator: record.twitterCreator,
|
|
3943
|
-
canonicalUrl: record.canonicalUrl,
|
|
3944
|
-
robots: record.robots,
|
|
3945
|
-
author: record.author,
|
|
3946
|
-
publishedTime: record.publishedTime,
|
|
3947
|
-
modifiedTime: record.modifiedTime,
|
|
3948
|
-
structuredData: record.structuredData,
|
|
3949
|
-
validationStatus: "pending",
|
|
3950
|
-
lastValidatedAt: void 0,
|
|
3951
|
-
validationErrors: void 0
|
|
3952
|
-
};
|
|
3953
|
-
this.records.push(newRecord);
|
|
3954
|
-
await this.save();
|
|
3955
|
-
return newRecord;
|
|
3956
|
-
}
|
|
3957
|
-
async updateRecord(record) {
|
|
3958
|
-
await this.ensureInitialized();
|
|
3959
|
-
const index = this.records.findIndex((r) => r.id === record.id);
|
|
3960
|
-
if (index === -1) {
|
|
3961
|
-
throw new Error(`SEO record with id ${record.id} not found`);
|
|
3962
|
-
}
|
|
3963
|
-
const updated = {
|
|
3964
|
-
...this.records[index],
|
|
3965
|
-
...record
|
|
3966
|
-
};
|
|
3967
|
-
this.records[index] = updated;
|
|
3968
|
-
await this.save();
|
|
3969
|
-
return updated;
|
|
3970
|
-
}
|
|
3971
|
-
async deleteRecord(id) {
|
|
3972
|
-
await this.ensureInitialized();
|
|
3973
|
-
const index = this.records.findIndex((r) => r.id === id);
|
|
3974
|
-
if (index === -1) {
|
|
3975
|
-
throw new Error(`SEO record with id ${id} not found`);
|
|
3976
|
-
}
|
|
3977
|
-
this.records.splice(index, 1);
|
|
3978
|
-
await this.save();
|
|
3979
|
-
}
|
|
3980
|
-
};
|
|
3981
3767
|
|
|
3982
3768
|
// src/lib/storage/storage-factory.ts
|
|
3983
|
-
function createStorageAdapter(config) {
|
|
3984
|
-
const filePath = config?.filePath || process.env.SEO_CONSOLE_STORAGE_PATH || "seo-records.json";
|
|
3985
|
-
return new FileStorage(filePath);
|
|
3986
|
-
}
|
|
3987
3769
|
function detectStorageConfig() {
|
|
3988
3770
|
return {
|
|
3989
3771
|
type: "file",
|
|
@@ -3998,22 +3780,16 @@ export {
|
|
|
3998
3780
|
CardFooter,
|
|
3999
3781
|
CardHeader,
|
|
4000
3782
|
CardTitle,
|
|
4001
|
-
FileStorage,
|
|
4002
3783
|
Input,
|
|
4003
3784
|
OGImagePreview,
|
|
4004
3785
|
SEORecordForm,
|
|
4005
3786
|
SEORecordList,
|
|
4006
3787
|
Spinner,
|
|
4007
3788
|
ValidationDashboard,
|
|
4008
|
-
crawlSiteForSEO,
|
|
4009
3789
|
createSEORecordSchema,
|
|
4010
|
-
createStorageAdapter,
|
|
4011
3790
|
detectStorageConfig,
|
|
4012
|
-
discoverNextJSRoutes,
|
|
4013
3791
|
extractMetadataFromHTML,
|
|
4014
|
-
extractMetadataFromURL,
|
|
4015
3792
|
extractSitemapFromRobotsTxt,
|
|
4016
|
-
generateExamplePaths,
|
|
4017
3793
|
generateRobotsTxt,
|
|
4018
3794
|
generateSitemapFromRecords,
|
|
4019
3795
|
generateSitemapXML,
|