rankdeploy-middleware 1.3.0 → 1.3.2
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/{chunk-ED7MGMJU.mjs → chunk-PZ4YPM2C.mjs} +17 -12
- package/dist/chunk-PZ4YPM2C.mjs.map +1 -0
- package/dist/express.js +16 -11
- package/dist/express.js.map +1 -1
- package/dist/express.mjs +1 -1
- package/dist/index.js +16 -11
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1 -1
- package/dist/netlify.js +16 -11
- package/dist/netlify.js.map +1 -1
- package/dist/netlify.mjs +1 -1
- package/dist/next.js +16 -11
- package/dist/next.js.map +1 -1
- package/dist/next.mjs +1 -1
- package/package.json +1 -1
- package/dist/chunk-ED7MGMJU.mjs.map +0 -1
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
var RANKDEPLOY_API = "https://proxy.unikium.com";
|
|
3
3
|
var STATIC_EXTENSIONS = /\.(js|css|png|jpg|jpeg|gif|svg|ico|woff|woff2|ttf|eot|map|json|xml|txt|mp4|webm|pdf|zip)$/i;
|
|
4
4
|
var BOT_USER_AGENTS = [
|
|
5
|
+
// Search engines
|
|
5
6
|
"googlebot",
|
|
6
7
|
"bingbot",
|
|
7
8
|
"yandexbot",
|
|
@@ -10,6 +11,7 @@ var BOT_USER_AGENTS = [
|
|
|
10
11
|
"slurp",
|
|
11
12
|
"sogou",
|
|
12
13
|
"exabot",
|
|
14
|
+
// Social media crawlers
|
|
13
15
|
"facebot",
|
|
14
16
|
"facebookexternalhit",
|
|
15
17
|
"twitterbot",
|
|
@@ -20,30 +22,33 @@ var BOT_USER_AGENTS = [
|
|
|
20
22
|
"discordbot",
|
|
21
23
|
"slackbot",
|
|
22
24
|
"pinterest",
|
|
25
|
+
// SEO tools & OG checkers
|
|
23
26
|
"screaming frog",
|
|
24
27
|
"ahrefs",
|
|
25
28
|
"semrush",
|
|
26
29
|
"moz.com",
|
|
27
30
|
"rogerbot",
|
|
28
31
|
"dotbot",
|
|
32
|
+
"opengraphcheck",
|
|
33
|
+
"og-check",
|
|
34
|
+
"metatag",
|
|
35
|
+
"linkpreview",
|
|
36
|
+
"previewbot",
|
|
37
|
+
"seobot",
|
|
38
|
+
"seositecheckup",
|
|
39
|
+
"sitecheck",
|
|
40
|
+
"seranking",
|
|
41
|
+
// AI bots
|
|
29
42
|
"gptbot",
|
|
30
43
|
"chatgpt",
|
|
31
44
|
"anthropic",
|
|
32
45
|
"claudebot",
|
|
33
46
|
"perplexitybot",
|
|
34
47
|
"cohere",
|
|
35
|
-
//
|
|
36
|
-
"
|
|
37
|
-
"metatags",
|
|
38
|
-
"preview",
|
|
39
|
-
"crawler",
|
|
48
|
+
// Generic bot indicators
|
|
49
|
+
"bot/",
|
|
40
50
|
"spider",
|
|
41
|
-
"
|
|
42
|
-
"curl",
|
|
43
|
-
"wget",
|
|
44
|
-
"python-requests",
|
|
45
|
-
"node-fetch",
|
|
46
|
-
"axios"
|
|
51
|
+
"crawl"
|
|
47
52
|
];
|
|
48
53
|
function isBot(userAgent, extraBots) {
|
|
49
54
|
const ua = userAgent.toLowerCase();
|
|
@@ -87,4 +92,4 @@ export {
|
|
|
87
92
|
isExcluded,
|
|
88
93
|
fetchPrerendered
|
|
89
94
|
};
|
|
90
|
-
//# sourceMappingURL=chunk-
|
|
95
|
+
//# sourceMappingURL=chunk-PZ4YPM2C.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["/**\n * rankdeploy-middleware — Core SEO middleware engine\n *\n * Serves pre-rendered HTML with SEO overrides to all visitors.\n * The pre-rendered HTML is visually identical to the original page\n * but includes injected meta tags (title, description, canonical, og:tags).\n */\n\nexport const RANKDEPLOY_API = \"https://proxy.unikium.com\";\n\nexport const STATIC_EXTENSIONS = /\\.(js|css|png|jpg|jpeg|gif|svg|ico|woff|woff2|ttf|eot|map|json|xml|txt|mp4|webm|pdf|zip)$/i;\n\nexport interface RankDeployOptions {\n /** Your site key from Rank Deploy dashboard (required) */\n siteKey: string;\n /** Rank Deploy API URL. Default: https://proxy.unikium.com */\n apiUrl?: string;\n /** Paths to exclude from pre-rendering */\n excludePaths?: string[];\n /** Only serve to bots (default: false — serves to everyone for OG checker compatibility) */\n botsOnly?: boolean;\n /** Additional bot user agents to detect (used when botsOnly=true) */\n extraBots?: string[];\n}\n\nexport const BOT_USER_AGENTS = [\n // Search engines\n \"googlebot\", \"bingbot\", \"yandexbot\", \"duckduckbot\", \"baiduspider\",\n \"slurp\", \"sogou\", \"exabot\",\n // Social media crawlers\n \"facebot\", \"facebookexternalhit\", \"twitterbot\", \"linkedinbot\",\n \"whatsapp\", \"telegrambot\", \"applebot\", \"discordbot\", \"slackbot\", \"pinterest\",\n // SEO tools & OG checkers\n \"screaming frog\", \"ahrefs\", \"semrush\", \"moz.com\", \"rogerbot\", \"dotbot\",\n \"opengraphcheck\", \"og-check\", \"metatag\", \"linkpreview\", \"previewbot\",\n \"seobot\", \"seositecheckup\", \"sitecheck\", \"seranking\",\n // AI bots\n \"gptbot\", \"chatgpt\", \"anthropic\", \"claudebot\", \"perplexitybot\", \"cohere\",\n // Generic bot indicators\n \"bot/\", \"spider\", \"crawl\",\n];\n\nexport function isBot(userAgent: string, extraBots?: string[]): boolean {\n const ua = userAgent.toLowerCase();\n const allBots = extraBots ? [...BOT_USER_AGENTS, ...extraBots] : BOT_USER_AGENTS;\n return allBots.some((bot) => ua.includes(bot));\n}\n\nexport function isStaticAsset(pathname: string): boolean {\n return STATIC_EXTENSIONS.test(pathname);\n}\n\nexport function isExcluded(pathname: string, excludePaths?: string[]): boolean {\n if (!excludePaths) return false;\n return excludePaths.some((p) => pathname.startsWith(p));\n}\n\n/**\n * Fetch pre-rendered HTML from Rank Deploy API.\n */\nexport async function fetchPrerendered(\n url: string,\n userAgent: string,\n siteKey: string,\n apiUrl = RANKDEPLOY_API,\n): Promise<string | null> {\n try {\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), 10000);\n\n const res = await fetch(\n `${apiUrl}/render?url=${encodeURIComponent(url)}&key=${encodeURIComponent(siteKey)}`,\n {\n headers: { \"User-Agent\": userAgent || \"Googlebot/2.1\" },\n signal: controller.signal,\n },\n );\n\n clearTimeout(timer);\n\n if (res.status === 200) {\n return res.text();\n }\n return null;\n } catch {\n return null;\n }\n}\n"],"mappings":";AAQO,IAAM,iBAAiB;AAEvB,IAAM,oBAAoB;AAe1B,IAAM,kBAAkB;AAAA;AAAA,EAE7B;AAAA,EAAa;AAAA,EAAW;AAAA,EAAa;AAAA,EAAe;AAAA,EACpD;AAAA,EAAS;AAAA,EAAS;AAAA;AAAA,EAElB;AAAA,EAAW;AAAA,EAAuB;AAAA,EAAc;AAAA,EAChD;AAAA,EAAY;AAAA,EAAe;AAAA,EAAY;AAAA,EAAc;AAAA,EAAY;AAAA;AAAA,EAEjE;AAAA,EAAkB;AAAA,EAAU;AAAA,EAAW;AAAA,EAAW;AAAA,EAAY;AAAA,EAC9D;AAAA,EAAkB;AAAA,EAAY;AAAA,EAAW;AAAA,EAAe;AAAA,EACxD;AAAA,EAAU;AAAA,EAAkB;AAAA,EAAa;AAAA;AAAA,EAEzC;AAAA,EAAU;AAAA,EAAW;AAAA,EAAa;AAAA,EAAa;AAAA,EAAiB;AAAA;AAAA,EAEhE;AAAA,EAAQ;AAAA,EAAU;AACpB;AAEO,SAAS,MAAM,WAAmB,WAA+B;AACtE,QAAM,KAAK,UAAU,YAAY;AACjC,QAAM,UAAU,YAAY,CAAC,GAAG,iBAAiB,GAAG,SAAS,IAAI;AACjE,SAAO,QAAQ,KAAK,CAAC,QAAQ,GAAG,SAAS,GAAG,CAAC;AAC/C;AAEO,SAAS,cAAc,UAA2B;AACvD,SAAO,kBAAkB,KAAK,QAAQ;AACxC;AAEO,SAAS,WAAW,UAAkB,cAAkC;AAC7E,MAAI,CAAC,aAAc,QAAO;AAC1B,SAAO,aAAa,KAAK,CAAC,MAAM,SAAS,WAAW,CAAC,CAAC;AACxD;AAKA,eAAsB,iBACpB,KACA,WACA,SACA,SAAS,gBACe;AACxB,MAAI;AACF,UAAM,aAAa,IAAI,gBAAgB;AACvC,UAAM,QAAQ,WAAW,MAAM,WAAW,MAAM,GAAG,GAAK;AAExD,UAAM,MAAM,MAAM;AAAA,MAChB,GAAG,MAAM,eAAe,mBAAmB,GAAG,CAAC,QAAQ,mBAAmB,OAAO,CAAC;AAAA,MAClF;AAAA,QACE,SAAS,EAAE,cAAc,aAAa,gBAAgB;AAAA,QACtD,QAAQ,WAAW;AAAA,MACrB;AAAA,IACF;AAEA,iBAAa,KAAK;AAElB,QAAI,IAAI,WAAW,KAAK;AACtB,aAAO,IAAI,KAAK;AAAA,IAClB;AACA,WAAO;AAAA,EACT,QAAQ;AACN,WAAO;AAAA,EACT;AACF;","names":[]}
|
package/dist/express.js
CHANGED
|
@@ -29,6 +29,7 @@ module.exports = __toCommonJS(express_exports);
|
|
|
29
29
|
var RANKDEPLOY_API = "https://proxy.unikium.com";
|
|
30
30
|
var STATIC_EXTENSIONS = /\.(js|css|png|jpg|jpeg|gif|svg|ico|woff|woff2|ttf|eot|map|json|xml|txt|mp4|webm|pdf|zip)$/i;
|
|
31
31
|
var BOT_USER_AGENTS = [
|
|
32
|
+
// Search engines
|
|
32
33
|
"googlebot",
|
|
33
34
|
"bingbot",
|
|
34
35
|
"yandexbot",
|
|
@@ -37,6 +38,7 @@ var BOT_USER_AGENTS = [
|
|
|
37
38
|
"slurp",
|
|
38
39
|
"sogou",
|
|
39
40
|
"exabot",
|
|
41
|
+
// Social media crawlers
|
|
40
42
|
"facebot",
|
|
41
43
|
"facebookexternalhit",
|
|
42
44
|
"twitterbot",
|
|
@@ -47,30 +49,33 @@ var BOT_USER_AGENTS = [
|
|
|
47
49
|
"discordbot",
|
|
48
50
|
"slackbot",
|
|
49
51
|
"pinterest",
|
|
52
|
+
// SEO tools & OG checkers
|
|
50
53
|
"screaming frog",
|
|
51
54
|
"ahrefs",
|
|
52
55
|
"semrush",
|
|
53
56
|
"moz.com",
|
|
54
57
|
"rogerbot",
|
|
55
58
|
"dotbot",
|
|
59
|
+
"opengraphcheck",
|
|
60
|
+
"og-check",
|
|
61
|
+
"metatag",
|
|
62
|
+
"linkpreview",
|
|
63
|
+
"previewbot",
|
|
64
|
+
"seobot",
|
|
65
|
+
"seositecheckup",
|
|
66
|
+
"sitecheck",
|
|
67
|
+
"seranking",
|
|
68
|
+
// AI bots
|
|
56
69
|
"gptbot",
|
|
57
70
|
"chatgpt",
|
|
58
71
|
"anthropic",
|
|
59
72
|
"claudebot",
|
|
60
73
|
"perplexitybot",
|
|
61
74
|
"cohere",
|
|
62
|
-
//
|
|
63
|
-
"
|
|
64
|
-
"metatags",
|
|
65
|
-
"preview",
|
|
66
|
-
"crawler",
|
|
75
|
+
// Generic bot indicators
|
|
76
|
+
"bot/",
|
|
67
77
|
"spider",
|
|
68
|
-
"
|
|
69
|
-
"curl",
|
|
70
|
-
"wget",
|
|
71
|
-
"python-requests",
|
|
72
|
-
"node-fetch",
|
|
73
|
-
"axios"
|
|
78
|
+
"crawl"
|
|
74
79
|
];
|
|
75
80
|
function isBot(userAgent, extraBots) {
|
|
76
81
|
const ua = userAgent.toLowerCase();
|
package/dist/express.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/express.ts","../src/index.ts"],"sourcesContent":["/**\n * rankdeploy-middleware/express — Express.js middleware\n */\n\nimport { isBot, isStaticAsset, isExcluded, fetchPrerendered, type RankDeployOptions } from \"./index\";\n\ninterface ExpressRequest {\n headers: Record<string, string | string[] | undefined>;\n url: string;\n protocol: string;\n get?(name: string): string | undefined;\n}\n\ninterface ExpressResponse {\n set(name: string, value: string): void;\n status(code: number): ExpressResponse;\n send(body: string): void;\n}\n\ntype NextFunction = () => void;\n\nexport function rankdeploy(options: RankDeployOptions) {\n return async function middleware(req: ExpressRequest, res: ExpressResponse, next: NextFunction) {\n const userAgent = (req.headers[\"user-agent\"] as string) || req.get?.(\"user-agent\") || \"\";\n const pathname = req.url.split(\"?\")[0];\n\n if (isStaticAsset(pathname) || isExcluded(pathname, options.excludePaths)) {\n return next();\n }\n\n if (options.botsOnly !== false && !isBot(userAgent, options.extraBots)) {\n return next();\n }\n\n const protocol = req.protocol || \"https\";\n const host = req.get?.(\"host\") || req.headers.host || \"\";\n const fullUrl = `${protocol}://${host}${req.url}`;\n\n const html = await fetchPrerendered(fullUrl, userAgent, options.siteKey, options.apiUrl);\n\n if (html) {\n res.set(\"Content-Type\", \"text/html; charset=utf-8\");\n res.set(\"X-Prerendered\", \"true\");\n res.set(\"X-Powered-By\", \"Rank Deploy\");\n return res.status(200).send(html);\n }\n\n next();\n };\n}\n\nexport default rankdeploy;\n","/**\n * rankdeploy-middleware — Core SEO middleware engine\n *\n * Serves pre-rendered HTML with SEO overrides to all visitors.\n * The pre-rendered HTML is visually identical to the original page\n * but includes injected meta tags (title, description, canonical, og:tags).\n */\n\nexport const RANKDEPLOY_API = \"https://proxy.unikium.com\";\n\nexport const STATIC_EXTENSIONS = /\\.(js|css|png|jpg|jpeg|gif|svg|ico|woff|woff2|ttf|eot|map|json|xml|txt|mp4|webm|pdf|zip)$/i;\n\nexport interface RankDeployOptions {\n /** Your site key from Rank Deploy dashboard (required) */\n siteKey: string;\n /** Rank Deploy API URL. Default: https://proxy.unikium.com */\n apiUrl?: string;\n /** Paths to exclude from pre-rendering */\n excludePaths?: string[];\n /** Only serve to bots (default: false — serves to everyone for OG checker compatibility) */\n botsOnly?: boolean;\n /** Additional bot user agents to detect (used when botsOnly=true) */\n extraBots?: string[];\n}\n\nexport const BOT_USER_AGENTS = [\n \"googlebot\", \"bingbot\", \"yandexbot\", \"duckduckbot\", \"baiduspider\",\n \"slurp\", \"sogou\", \"exabot\",\n \"facebot\", \"facebookexternalhit\", \"twitterbot\", \"linkedinbot\",\n \"whatsapp\", \"telegrambot\", \"applebot\", \"discordbot\", \"slackbot\", \"pinterest\",\n \"screaming frog\", \"ahrefs\", \"semrush\", \"moz.com\", \"rogerbot\", \"dotbot\",\n \"
|
|
1
|
+
{"version":3,"sources":["../src/express.ts","../src/index.ts"],"sourcesContent":["/**\n * rankdeploy-middleware/express — Express.js middleware\n */\n\nimport { isBot, isStaticAsset, isExcluded, fetchPrerendered, type RankDeployOptions } from \"./index\";\n\ninterface ExpressRequest {\n headers: Record<string, string | string[] | undefined>;\n url: string;\n protocol: string;\n get?(name: string): string | undefined;\n}\n\ninterface ExpressResponse {\n set(name: string, value: string): void;\n status(code: number): ExpressResponse;\n send(body: string): void;\n}\n\ntype NextFunction = () => void;\n\nexport function rankdeploy(options: RankDeployOptions) {\n return async function middleware(req: ExpressRequest, res: ExpressResponse, next: NextFunction) {\n const userAgent = (req.headers[\"user-agent\"] as string) || req.get?.(\"user-agent\") || \"\";\n const pathname = req.url.split(\"?\")[0];\n\n if (isStaticAsset(pathname) || isExcluded(pathname, options.excludePaths)) {\n return next();\n }\n\n if (options.botsOnly !== false && !isBot(userAgent, options.extraBots)) {\n return next();\n }\n\n const protocol = req.protocol || \"https\";\n const host = req.get?.(\"host\") || req.headers.host || \"\";\n const fullUrl = `${protocol}://${host}${req.url}`;\n\n const html = await fetchPrerendered(fullUrl, userAgent, options.siteKey, options.apiUrl);\n\n if (html) {\n res.set(\"Content-Type\", \"text/html; charset=utf-8\");\n res.set(\"X-Prerendered\", \"true\");\n res.set(\"X-Powered-By\", \"Rank Deploy\");\n return res.status(200).send(html);\n }\n\n next();\n };\n}\n\nexport default rankdeploy;\n","/**\n * rankdeploy-middleware — Core SEO middleware engine\n *\n * Serves pre-rendered HTML with SEO overrides to all visitors.\n * The pre-rendered HTML is visually identical to the original page\n * but includes injected meta tags (title, description, canonical, og:tags).\n */\n\nexport const RANKDEPLOY_API = \"https://proxy.unikium.com\";\n\nexport const STATIC_EXTENSIONS = /\\.(js|css|png|jpg|jpeg|gif|svg|ico|woff|woff2|ttf|eot|map|json|xml|txt|mp4|webm|pdf|zip)$/i;\n\nexport interface RankDeployOptions {\n /** Your site key from Rank Deploy dashboard (required) */\n siteKey: string;\n /** Rank Deploy API URL. Default: https://proxy.unikium.com */\n apiUrl?: string;\n /** Paths to exclude from pre-rendering */\n excludePaths?: string[];\n /** Only serve to bots (default: false — serves to everyone for OG checker compatibility) */\n botsOnly?: boolean;\n /** Additional bot user agents to detect (used when botsOnly=true) */\n extraBots?: string[];\n}\n\nexport const BOT_USER_AGENTS = [\n // Search engines\n \"googlebot\", \"bingbot\", \"yandexbot\", \"duckduckbot\", \"baiduspider\",\n \"slurp\", \"sogou\", \"exabot\",\n // Social media crawlers\n \"facebot\", \"facebookexternalhit\", \"twitterbot\", \"linkedinbot\",\n \"whatsapp\", \"telegrambot\", \"applebot\", \"discordbot\", \"slackbot\", \"pinterest\",\n // SEO tools & OG checkers\n \"screaming frog\", \"ahrefs\", \"semrush\", \"moz.com\", \"rogerbot\", \"dotbot\",\n \"opengraphcheck\", \"og-check\", \"metatag\", \"linkpreview\", \"previewbot\",\n \"seobot\", \"seositecheckup\", \"sitecheck\", \"seranking\",\n // AI bots\n \"gptbot\", \"chatgpt\", \"anthropic\", \"claudebot\", \"perplexitybot\", \"cohere\",\n // Generic bot indicators\n \"bot/\", \"spider\", \"crawl\",\n];\n\nexport function isBot(userAgent: string, extraBots?: string[]): boolean {\n const ua = userAgent.toLowerCase();\n const allBots = extraBots ? [...BOT_USER_AGENTS, ...extraBots] : BOT_USER_AGENTS;\n return allBots.some((bot) => ua.includes(bot));\n}\n\nexport function isStaticAsset(pathname: string): boolean {\n return STATIC_EXTENSIONS.test(pathname);\n}\n\nexport function isExcluded(pathname: string, excludePaths?: string[]): boolean {\n if (!excludePaths) return false;\n return excludePaths.some((p) => pathname.startsWith(p));\n}\n\n/**\n * Fetch pre-rendered HTML from Rank Deploy API.\n */\nexport async function fetchPrerendered(\n url: string,\n userAgent: string,\n siteKey: string,\n apiUrl = RANKDEPLOY_API,\n): Promise<string | null> {\n try {\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), 10000);\n\n const res = await fetch(\n `${apiUrl}/render?url=${encodeURIComponent(url)}&key=${encodeURIComponent(siteKey)}`,\n {\n headers: { \"User-Agent\": userAgent || \"Googlebot/2.1\" },\n signal: controller.signal,\n },\n );\n\n clearTimeout(timer);\n\n if (res.status === 200) {\n return res.text();\n }\n return null;\n } catch {\n return null;\n }\n}\n"],"mappings":"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","names":[]}
|
package/dist/express.mjs
CHANGED
package/dist/index.js
CHANGED
|
@@ -32,6 +32,7 @@ module.exports = __toCommonJS(src_exports);
|
|
|
32
32
|
var RANKDEPLOY_API = "https://proxy.unikium.com";
|
|
33
33
|
var STATIC_EXTENSIONS = /\.(js|css|png|jpg|jpeg|gif|svg|ico|woff|woff2|ttf|eot|map|json|xml|txt|mp4|webm|pdf|zip)$/i;
|
|
34
34
|
var BOT_USER_AGENTS = [
|
|
35
|
+
// Search engines
|
|
35
36
|
"googlebot",
|
|
36
37
|
"bingbot",
|
|
37
38
|
"yandexbot",
|
|
@@ -40,6 +41,7 @@ var BOT_USER_AGENTS = [
|
|
|
40
41
|
"slurp",
|
|
41
42
|
"sogou",
|
|
42
43
|
"exabot",
|
|
44
|
+
// Social media crawlers
|
|
43
45
|
"facebot",
|
|
44
46
|
"facebookexternalhit",
|
|
45
47
|
"twitterbot",
|
|
@@ -50,30 +52,33 @@ var BOT_USER_AGENTS = [
|
|
|
50
52
|
"discordbot",
|
|
51
53
|
"slackbot",
|
|
52
54
|
"pinterest",
|
|
55
|
+
// SEO tools & OG checkers
|
|
53
56
|
"screaming frog",
|
|
54
57
|
"ahrefs",
|
|
55
58
|
"semrush",
|
|
56
59
|
"moz.com",
|
|
57
60
|
"rogerbot",
|
|
58
61
|
"dotbot",
|
|
62
|
+
"opengraphcheck",
|
|
63
|
+
"og-check",
|
|
64
|
+
"metatag",
|
|
65
|
+
"linkpreview",
|
|
66
|
+
"previewbot",
|
|
67
|
+
"seobot",
|
|
68
|
+
"seositecheckup",
|
|
69
|
+
"sitecheck",
|
|
70
|
+
"seranking",
|
|
71
|
+
// AI bots
|
|
59
72
|
"gptbot",
|
|
60
73
|
"chatgpt",
|
|
61
74
|
"anthropic",
|
|
62
75
|
"claudebot",
|
|
63
76
|
"perplexitybot",
|
|
64
77
|
"cohere",
|
|
65
|
-
//
|
|
66
|
-
"
|
|
67
|
-
"metatags",
|
|
68
|
-
"preview",
|
|
69
|
-
"crawler",
|
|
78
|
+
// Generic bot indicators
|
|
79
|
+
"bot/",
|
|
70
80
|
"spider",
|
|
71
|
-
"
|
|
72
|
-
"curl",
|
|
73
|
-
"wget",
|
|
74
|
-
"python-requests",
|
|
75
|
-
"node-fetch",
|
|
76
|
-
"axios"
|
|
81
|
+
"crawl"
|
|
77
82
|
];
|
|
78
83
|
function isBot(userAgent, extraBots) {
|
|
79
84
|
const ua = userAgent.toLowerCase();
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["/**\n * rankdeploy-middleware — Core SEO middleware engine\n *\n * Serves pre-rendered HTML with SEO overrides to all visitors.\n * The pre-rendered HTML is visually identical to the original page\n * but includes injected meta tags (title, description, canonical, og:tags).\n */\n\nexport const RANKDEPLOY_API = \"https://proxy.unikium.com\";\n\nexport const STATIC_EXTENSIONS = /\\.(js|css|png|jpg|jpeg|gif|svg|ico|woff|woff2|ttf|eot|map|json|xml|txt|mp4|webm|pdf|zip)$/i;\n\nexport interface RankDeployOptions {\n /** Your site key from Rank Deploy dashboard (required) */\n siteKey: string;\n /** Rank Deploy API URL. Default: https://proxy.unikium.com */\n apiUrl?: string;\n /** Paths to exclude from pre-rendering */\n excludePaths?: string[];\n /** Only serve to bots (default: false — serves to everyone for OG checker compatibility) */\n botsOnly?: boolean;\n /** Additional bot user agents to detect (used when botsOnly=true) */\n extraBots?: string[];\n}\n\nexport const BOT_USER_AGENTS = [\n \"googlebot\", \"bingbot\", \"yandexbot\", \"duckduckbot\", \"baiduspider\",\n \"slurp\", \"sogou\", \"exabot\",\n \"facebot\", \"facebookexternalhit\", \"twitterbot\", \"linkedinbot\",\n \"whatsapp\", \"telegrambot\", \"applebot\", \"discordbot\", \"slackbot\", \"pinterest\",\n \"screaming frog\", \"ahrefs\", \"semrush\", \"moz.com\", \"rogerbot\", \"dotbot\",\n \"
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["/**\n * rankdeploy-middleware — Core SEO middleware engine\n *\n * Serves pre-rendered HTML with SEO overrides to all visitors.\n * The pre-rendered HTML is visually identical to the original page\n * but includes injected meta tags (title, description, canonical, og:tags).\n */\n\nexport const RANKDEPLOY_API = \"https://proxy.unikium.com\";\n\nexport const STATIC_EXTENSIONS = /\\.(js|css|png|jpg|jpeg|gif|svg|ico|woff|woff2|ttf|eot|map|json|xml|txt|mp4|webm|pdf|zip)$/i;\n\nexport interface RankDeployOptions {\n /** Your site key from Rank Deploy dashboard (required) */\n siteKey: string;\n /** Rank Deploy API URL. Default: https://proxy.unikium.com */\n apiUrl?: string;\n /** Paths to exclude from pre-rendering */\n excludePaths?: string[];\n /** Only serve to bots (default: false — serves to everyone for OG checker compatibility) */\n botsOnly?: boolean;\n /** Additional bot user agents to detect (used when botsOnly=true) */\n extraBots?: string[];\n}\n\nexport const BOT_USER_AGENTS = [\n // Search engines\n \"googlebot\", \"bingbot\", \"yandexbot\", \"duckduckbot\", \"baiduspider\",\n \"slurp\", \"sogou\", \"exabot\",\n // Social media crawlers\n \"facebot\", \"facebookexternalhit\", \"twitterbot\", \"linkedinbot\",\n \"whatsapp\", \"telegrambot\", \"applebot\", \"discordbot\", \"slackbot\", \"pinterest\",\n // SEO tools & OG checkers\n \"screaming frog\", \"ahrefs\", \"semrush\", \"moz.com\", \"rogerbot\", \"dotbot\",\n \"opengraphcheck\", \"og-check\", \"metatag\", \"linkpreview\", \"previewbot\",\n \"seobot\", \"seositecheckup\", \"sitecheck\", \"seranking\",\n // AI bots\n \"gptbot\", \"chatgpt\", \"anthropic\", \"claudebot\", \"perplexitybot\", \"cohere\",\n // Generic bot indicators\n \"bot/\", \"spider\", \"crawl\",\n];\n\nexport function isBot(userAgent: string, extraBots?: string[]): boolean {\n const ua = userAgent.toLowerCase();\n const allBots = extraBots ? [...BOT_USER_AGENTS, ...extraBots] : BOT_USER_AGENTS;\n return allBots.some((bot) => ua.includes(bot));\n}\n\nexport function isStaticAsset(pathname: string): boolean {\n return STATIC_EXTENSIONS.test(pathname);\n}\n\nexport function isExcluded(pathname: string, excludePaths?: string[]): boolean {\n if (!excludePaths) return false;\n return excludePaths.some((p) => pathname.startsWith(p));\n}\n\n/**\n * Fetch pre-rendered HTML from Rank Deploy API.\n */\nexport async function fetchPrerendered(\n url: string,\n userAgent: string,\n siteKey: string,\n apiUrl = RANKDEPLOY_API,\n): Promise<string | null> {\n try {\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), 10000);\n\n const res = await fetch(\n `${apiUrl}/render?url=${encodeURIComponent(url)}&key=${encodeURIComponent(siteKey)}`,\n {\n headers: { \"User-Agent\": userAgent || \"Googlebot/2.1\" },\n signal: controller.signal,\n },\n );\n\n clearTimeout(timer);\n\n if (res.status === 200) {\n return res.text();\n }\n return null;\n } catch {\n return null;\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAQO,IAAM,iBAAiB;AAEvB,IAAM,oBAAoB;AAe1B,IAAM,kBAAkB;AAAA;AAAA,EAE7B;AAAA,EAAa;AAAA,EAAW;AAAA,EAAa;AAAA,EAAe;AAAA,EACpD;AAAA,EAAS;AAAA,EAAS;AAAA;AAAA,EAElB;AAAA,EAAW;AAAA,EAAuB;AAAA,EAAc;AAAA,EAChD;AAAA,EAAY;AAAA,EAAe;AAAA,EAAY;AAAA,EAAc;AAAA,EAAY;AAAA;AAAA,EAEjE;AAAA,EAAkB;AAAA,EAAU;AAAA,EAAW;AAAA,EAAW;AAAA,EAAY;AAAA,EAC9D;AAAA,EAAkB;AAAA,EAAY;AAAA,EAAW;AAAA,EAAe;AAAA,EACxD;AAAA,EAAU;AAAA,EAAkB;AAAA,EAAa;AAAA;AAAA,EAEzC;AAAA,EAAU;AAAA,EAAW;AAAA,EAAa;AAAA,EAAa;AAAA,EAAiB;AAAA;AAAA,EAEhE;AAAA,EAAQ;AAAA,EAAU;AACpB;AAEO,SAAS,MAAM,WAAmB,WAA+B;AACtE,QAAM,KAAK,UAAU,YAAY;AACjC,QAAM,UAAU,YAAY,CAAC,GAAG,iBAAiB,GAAG,SAAS,IAAI;AACjE,SAAO,QAAQ,KAAK,CAAC,QAAQ,GAAG,SAAS,GAAG,CAAC;AAC/C;AAEO,SAAS,cAAc,UAA2B;AACvD,SAAO,kBAAkB,KAAK,QAAQ;AACxC;AAEO,SAAS,WAAW,UAAkB,cAAkC;AAC7E,MAAI,CAAC,aAAc,QAAO;AAC1B,SAAO,aAAa,KAAK,CAAC,MAAM,SAAS,WAAW,CAAC,CAAC;AACxD;AAKA,eAAsB,iBACpB,KACA,WACA,SACA,SAAS,gBACe;AACxB,MAAI;AACF,UAAM,aAAa,IAAI,gBAAgB;AACvC,UAAM,QAAQ,WAAW,MAAM,WAAW,MAAM,GAAG,GAAK;AAExD,UAAM,MAAM,MAAM;AAAA,MAChB,GAAG,MAAM,eAAe,mBAAmB,GAAG,CAAC,QAAQ,mBAAmB,OAAO,CAAC;AAAA,MAClF;AAAA,QACE,SAAS,EAAE,cAAc,aAAa,gBAAgB;AAAA,QACtD,QAAQ,WAAW;AAAA,MACrB;AAAA,IACF;AAEA,iBAAa,KAAK;AAElB,QAAI,IAAI,WAAW,KAAK;AACtB,aAAO,IAAI,KAAK;AAAA,IAClB;AACA,WAAO;AAAA,EACT,QAAQ;AACN,WAAO;AAAA,EACT;AACF;","names":[]}
|
package/dist/index.mjs
CHANGED
package/dist/netlify.js
CHANGED
|
@@ -28,6 +28,7 @@ module.exports = __toCommonJS(netlify_exports);
|
|
|
28
28
|
var RANKDEPLOY_API = "https://proxy.unikium.com";
|
|
29
29
|
var STATIC_EXTENSIONS = /\.(js|css|png|jpg|jpeg|gif|svg|ico|woff|woff2|ttf|eot|map|json|xml|txt|mp4|webm|pdf|zip)$/i;
|
|
30
30
|
var BOT_USER_AGENTS = [
|
|
31
|
+
// Search engines
|
|
31
32
|
"googlebot",
|
|
32
33
|
"bingbot",
|
|
33
34
|
"yandexbot",
|
|
@@ -36,6 +37,7 @@ var BOT_USER_AGENTS = [
|
|
|
36
37
|
"slurp",
|
|
37
38
|
"sogou",
|
|
38
39
|
"exabot",
|
|
40
|
+
// Social media crawlers
|
|
39
41
|
"facebot",
|
|
40
42
|
"facebookexternalhit",
|
|
41
43
|
"twitterbot",
|
|
@@ -46,30 +48,33 @@ var BOT_USER_AGENTS = [
|
|
|
46
48
|
"discordbot",
|
|
47
49
|
"slackbot",
|
|
48
50
|
"pinterest",
|
|
51
|
+
// SEO tools & OG checkers
|
|
49
52
|
"screaming frog",
|
|
50
53
|
"ahrefs",
|
|
51
54
|
"semrush",
|
|
52
55
|
"moz.com",
|
|
53
56
|
"rogerbot",
|
|
54
57
|
"dotbot",
|
|
58
|
+
"opengraphcheck",
|
|
59
|
+
"og-check",
|
|
60
|
+
"metatag",
|
|
61
|
+
"linkpreview",
|
|
62
|
+
"previewbot",
|
|
63
|
+
"seobot",
|
|
64
|
+
"seositecheckup",
|
|
65
|
+
"sitecheck",
|
|
66
|
+
"seranking",
|
|
67
|
+
// AI bots
|
|
55
68
|
"gptbot",
|
|
56
69
|
"chatgpt",
|
|
57
70
|
"anthropic",
|
|
58
71
|
"claudebot",
|
|
59
72
|
"perplexitybot",
|
|
60
73
|
"cohere",
|
|
61
|
-
//
|
|
62
|
-
"
|
|
63
|
-
"metatags",
|
|
64
|
-
"preview",
|
|
65
|
-
"crawler",
|
|
74
|
+
// Generic bot indicators
|
|
75
|
+
"bot/",
|
|
66
76
|
"spider",
|
|
67
|
-
"
|
|
68
|
-
"curl",
|
|
69
|
-
"wget",
|
|
70
|
-
"python-requests",
|
|
71
|
-
"node-fetch",
|
|
72
|
-
"axios"
|
|
77
|
+
"crawl"
|
|
73
78
|
];
|
|
74
79
|
function isBot(userAgent, extraBots) {
|
|
75
80
|
const ua = userAgent.toLowerCase();
|
package/dist/netlify.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/netlify.ts","../src/index.ts"],"sourcesContent":["/**\n * rankdeploy-middleware/netlify — Netlify Edge Function middleware\n */\n\nimport { isBot, isStaticAsset, isExcluded, fetchPrerendered, type RankDeployOptions } from \"./index\";\n\ninterface NetlifyContext {\n next(): Promise<Response>;\n}\n\nexport function createHandler(options: RankDeployOptions) {\n return async function handler(request: Request, context: NetlifyContext) {\n const userAgent = request.headers.get(\"user-agent\") || \"\";\n const pathname = new URL(request.url).pathname;\n\n if (isStaticAsset(pathname) || isExcluded(pathname, options.excludePaths)) {\n return context.next();\n }\n\n if (options.botsOnly !== false && !isBot(userAgent, options.extraBots)) {\n return context.next();\n }\n\n const html = await fetchPrerendered(request.url, userAgent, options.siteKey, options.apiUrl);\n\n if (html) {\n return new Response(html, {\n status: 200,\n headers: {\n \"Content-Type\": \"text/html; charset=utf-8\",\n \"X-Prerendered\": \"true\",\n \"X-Powered-By\": \"Rank Deploy\",\n },\n });\n }\n\n return context.next();\n };\n}\n","/**\n * rankdeploy-middleware — Core SEO middleware engine\n *\n * Serves pre-rendered HTML with SEO overrides to all visitors.\n * The pre-rendered HTML is visually identical to the original page\n * but includes injected meta tags (title, description, canonical, og:tags).\n */\n\nexport const RANKDEPLOY_API = \"https://proxy.unikium.com\";\n\nexport const STATIC_EXTENSIONS = /\\.(js|css|png|jpg|jpeg|gif|svg|ico|woff|woff2|ttf|eot|map|json|xml|txt|mp4|webm|pdf|zip)$/i;\n\nexport interface RankDeployOptions {\n /** Your site key from Rank Deploy dashboard (required) */\n siteKey: string;\n /** Rank Deploy API URL. Default: https://proxy.unikium.com */\n apiUrl?: string;\n /** Paths to exclude from pre-rendering */\n excludePaths?: string[];\n /** Only serve to bots (default: false — serves to everyone for OG checker compatibility) */\n botsOnly?: boolean;\n /** Additional bot user agents to detect (used when botsOnly=true) */\n extraBots?: string[];\n}\n\nexport const BOT_USER_AGENTS = [\n \"googlebot\", \"bingbot\", \"yandexbot\", \"duckduckbot\", \"baiduspider\",\n \"slurp\", \"sogou\", \"exabot\",\n \"facebot\", \"facebookexternalhit\", \"twitterbot\", \"linkedinbot\",\n \"whatsapp\", \"telegrambot\", \"applebot\", \"discordbot\", \"slackbot\", \"pinterest\",\n \"screaming frog\", \"ahrefs\", \"semrush\", \"moz.com\", \"rogerbot\", \"dotbot\",\n \"
|
|
1
|
+
{"version":3,"sources":["../src/netlify.ts","../src/index.ts"],"sourcesContent":["/**\n * rankdeploy-middleware/netlify — Netlify Edge Function middleware\n */\n\nimport { isBot, isStaticAsset, isExcluded, fetchPrerendered, type RankDeployOptions } from \"./index\";\n\ninterface NetlifyContext {\n next(): Promise<Response>;\n}\n\nexport function createHandler(options: RankDeployOptions) {\n return async function handler(request: Request, context: NetlifyContext) {\n const userAgent = request.headers.get(\"user-agent\") || \"\";\n const pathname = new URL(request.url).pathname;\n\n if (isStaticAsset(pathname) || isExcluded(pathname, options.excludePaths)) {\n return context.next();\n }\n\n if (options.botsOnly !== false && !isBot(userAgent, options.extraBots)) {\n return context.next();\n }\n\n const html = await fetchPrerendered(request.url, userAgent, options.siteKey, options.apiUrl);\n\n if (html) {\n return new Response(html, {\n status: 200,\n headers: {\n \"Content-Type\": \"text/html; charset=utf-8\",\n \"X-Prerendered\": \"true\",\n \"X-Powered-By\": \"Rank Deploy\",\n },\n });\n }\n\n return context.next();\n };\n}\n","/**\n * rankdeploy-middleware — Core SEO middleware engine\n *\n * Serves pre-rendered HTML with SEO overrides to all visitors.\n * The pre-rendered HTML is visually identical to the original page\n * but includes injected meta tags (title, description, canonical, og:tags).\n */\n\nexport const RANKDEPLOY_API = \"https://proxy.unikium.com\";\n\nexport const STATIC_EXTENSIONS = /\\.(js|css|png|jpg|jpeg|gif|svg|ico|woff|woff2|ttf|eot|map|json|xml|txt|mp4|webm|pdf|zip)$/i;\n\nexport interface RankDeployOptions {\n /** Your site key from Rank Deploy dashboard (required) */\n siteKey: string;\n /** Rank Deploy API URL. Default: https://proxy.unikium.com */\n apiUrl?: string;\n /** Paths to exclude from pre-rendering */\n excludePaths?: string[];\n /** Only serve to bots (default: false — serves to everyone for OG checker compatibility) */\n botsOnly?: boolean;\n /** Additional bot user agents to detect (used when botsOnly=true) */\n extraBots?: string[];\n}\n\nexport const BOT_USER_AGENTS = [\n // Search engines\n \"googlebot\", \"bingbot\", \"yandexbot\", \"duckduckbot\", \"baiduspider\",\n \"slurp\", \"sogou\", \"exabot\",\n // Social media crawlers\n \"facebot\", \"facebookexternalhit\", \"twitterbot\", \"linkedinbot\",\n \"whatsapp\", \"telegrambot\", \"applebot\", \"discordbot\", \"slackbot\", \"pinterest\",\n // SEO tools & OG checkers\n \"screaming frog\", \"ahrefs\", \"semrush\", \"moz.com\", \"rogerbot\", \"dotbot\",\n \"opengraphcheck\", \"og-check\", \"metatag\", \"linkpreview\", \"previewbot\",\n \"seobot\", \"seositecheckup\", \"sitecheck\", \"seranking\",\n // AI bots\n \"gptbot\", \"chatgpt\", \"anthropic\", \"claudebot\", \"perplexitybot\", \"cohere\",\n // Generic bot indicators\n \"bot/\", \"spider\", \"crawl\",\n];\n\nexport function isBot(userAgent: string, extraBots?: string[]): boolean {\n const ua = userAgent.toLowerCase();\n const allBots = extraBots ? [...BOT_USER_AGENTS, ...extraBots] : BOT_USER_AGENTS;\n return allBots.some((bot) => ua.includes(bot));\n}\n\nexport function isStaticAsset(pathname: string): boolean {\n return STATIC_EXTENSIONS.test(pathname);\n}\n\nexport function isExcluded(pathname: string, excludePaths?: string[]): boolean {\n if (!excludePaths) return false;\n return excludePaths.some((p) => pathname.startsWith(p));\n}\n\n/**\n * Fetch pre-rendered HTML from Rank Deploy API.\n */\nexport async function fetchPrerendered(\n url: string,\n userAgent: string,\n siteKey: string,\n apiUrl = RANKDEPLOY_API,\n): Promise<string | null> {\n try {\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), 10000);\n\n const res = await fetch(\n `${apiUrl}/render?url=${encodeURIComponent(url)}&key=${encodeURIComponent(siteKey)}`,\n {\n headers: { \"User-Agent\": userAgent || \"Googlebot/2.1\" },\n signal: controller.signal,\n },\n );\n\n clearTimeout(timer);\n\n if (res.status === 200) {\n return res.text();\n }\n return null;\n } catch {\n return null;\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACQO,IAAM,iBAAiB;AAEvB,IAAM,oBAAoB;AAe1B,IAAM,kBAAkB;AAAA;AAAA,EAE7B;AAAA,EAAa;AAAA,EAAW;AAAA,EAAa;AAAA,EAAe;AAAA,EACpD;AAAA,EAAS;AAAA,EAAS;AAAA;AAAA,EAElB;AAAA,EAAW;AAAA,EAAuB;AAAA,EAAc;AAAA,EAChD;AAAA,EAAY;AAAA,EAAe;AAAA,EAAY;AAAA,EAAc;AAAA,EAAY;AAAA;AAAA,EAEjE;AAAA,EAAkB;AAAA,EAAU;AAAA,EAAW;AAAA,EAAW;AAAA,EAAY;AAAA,EAC9D;AAAA,EAAkB;AAAA,EAAY;AAAA,EAAW;AAAA,EAAe;AAAA,EACxD;AAAA,EAAU;AAAA,EAAkB;AAAA,EAAa;AAAA;AAAA,EAEzC;AAAA,EAAU;AAAA,EAAW;AAAA,EAAa;AAAA,EAAa;AAAA,EAAiB;AAAA;AAAA,EAEhE;AAAA,EAAQ;AAAA,EAAU;AACpB;AAEO,SAAS,MAAM,WAAmB,WAA+B;AACtE,QAAM,KAAK,UAAU,YAAY;AACjC,QAAM,UAAU,YAAY,CAAC,GAAG,iBAAiB,GAAG,SAAS,IAAI;AACjE,SAAO,QAAQ,KAAK,CAAC,QAAQ,GAAG,SAAS,GAAG,CAAC;AAC/C;AAEO,SAAS,cAAc,UAA2B;AACvD,SAAO,kBAAkB,KAAK,QAAQ;AACxC;AAEO,SAAS,WAAW,UAAkB,cAAkC;AAC7E,MAAI,CAAC,aAAc,QAAO;AAC1B,SAAO,aAAa,KAAK,CAAC,MAAM,SAAS,WAAW,CAAC,CAAC;AACxD;AAKA,eAAsB,iBACpB,KACA,WACA,SACA,SAAS,gBACe;AACxB,MAAI;AACF,UAAM,aAAa,IAAI,gBAAgB;AACvC,UAAM,QAAQ,WAAW,MAAM,WAAW,MAAM,GAAG,GAAK;AAExD,UAAM,MAAM,MAAM;AAAA,MAChB,GAAG,MAAM,eAAe,mBAAmB,GAAG,CAAC,QAAQ,mBAAmB,OAAO,CAAC;AAAA,MAClF;AAAA,QACE,SAAS,EAAE,cAAc,aAAa,gBAAgB;AAAA,QACtD,QAAQ,WAAW;AAAA,MACrB;AAAA,IACF;AAEA,iBAAa,KAAK;AAElB,QAAI,IAAI,WAAW,KAAK;AACtB,aAAO,IAAI,KAAK;AAAA,IAClB;AACA,WAAO;AAAA,EACT,QAAQ;AACN,WAAO;AAAA,EACT;AACF;;;AD7EO,SAAS,cAAc,SAA4B;AACxD,SAAO,eAAe,QAAQ,SAAkB,SAAyB;AACvE,UAAM,YAAY,QAAQ,QAAQ,IAAI,YAAY,KAAK;AACvD,UAAM,WAAW,IAAI,IAAI,QAAQ,GAAG,EAAE;AAEtC,QAAI,cAAc,QAAQ,KAAK,WAAW,UAAU,QAAQ,YAAY,GAAG;AACzE,aAAO,QAAQ,KAAK;AAAA,IACtB;AAEA,QAAI,QAAQ,aAAa,SAAS,CAAC,MAAM,WAAW,QAAQ,SAAS,GAAG;AACtE,aAAO,QAAQ,KAAK;AAAA,IACtB;AAEA,UAAM,OAAO,MAAM,iBAAiB,QAAQ,KAAK,WAAW,QAAQ,SAAS,QAAQ,MAAM;AAE3F,QAAI,MAAM;AACR,aAAO,IAAI,SAAS,MAAM;AAAA,QACxB,QAAQ;AAAA,QACR,SAAS;AAAA,UACP,gBAAgB;AAAA,UAChB,iBAAiB;AAAA,UACjB,gBAAgB;AAAA,QAClB;AAAA,MACF,CAAC;AAAA,IACH;AAEA,WAAO,QAAQ,KAAK;AAAA,EACtB;AACF;","names":[]}
|
package/dist/netlify.mjs
CHANGED
package/dist/next.js
CHANGED
|
@@ -29,6 +29,7 @@ module.exports = __toCommonJS(next_exports);
|
|
|
29
29
|
var RANKDEPLOY_API = "https://proxy.unikium.com";
|
|
30
30
|
var STATIC_EXTENSIONS = /\.(js|css|png|jpg|jpeg|gif|svg|ico|woff|woff2|ttf|eot|map|json|xml|txt|mp4|webm|pdf|zip)$/i;
|
|
31
31
|
var BOT_USER_AGENTS = [
|
|
32
|
+
// Search engines
|
|
32
33
|
"googlebot",
|
|
33
34
|
"bingbot",
|
|
34
35
|
"yandexbot",
|
|
@@ -37,6 +38,7 @@ var BOT_USER_AGENTS = [
|
|
|
37
38
|
"slurp",
|
|
38
39
|
"sogou",
|
|
39
40
|
"exabot",
|
|
41
|
+
// Social media crawlers
|
|
40
42
|
"facebot",
|
|
41
43
|
"facebookexternalhit",
|
|
42
44
|
"twitterbot",
|
|
@@ -47,30 +49,33 @@ var BOT_USER_AGENTS = [
|
|
|
47
49
|
"discordbot",
|
|
48
50
|
"slackbot",
|
|
49
51
|
"pinterest",
|
|
52
|
+
// SEO tools & OG checkers
|
|
50
53
|
"screaming frog",
|
|
51
54
|
"ahrefs",
|
|
52
55
|
"semrush",
|
|
53
56
|
"moz.com",
|
|
54
57
|
"rogerbot",
|
|
55
58
|
"dotbot",
|
|
59
|
+
"opengraphcheck",
|
|
60
|
+
"og-check",
|
|
61
|
+
"metatag",
|
|
62
|
+
"linkpreview",
|
|
63
|
+
"previewbot",
|
|
64
|
+
"seobot",
|
|
65
|
+
"seositecheckup",
|
|
66
|
+
"sitecheck",
|
|
67
|
+
"seranking",
|
|
68
|
+
// AI bots
|
|
56
69
|
"gptbot",
|
|
57
70
|
"chatgpt",
|
|
58
71
|
"anthropic",
|
|
59
72
|
"claudebot",
|
|
60
73
|
"perplexitybot",
|
|
61
74
|
"cohere",
|
|
62
|
-
//
|
|
63
|
-
"
|
|
64
|
-
"metatags",
|
|
65
|
-
"preview",
|
|
66
|
-
"crawler",
|
|
75
|
+
// Generic bot indicators
|
|
76
|
+
"bot/",
|
|
67
77
|
"spider",
|
|
68
|
-
"
|
|
69
|
-
"curl",
|
|
70
|
-
"wget",
|
|
71
|
-
"python-requests",
|
|
72
|
-
"node-fetch",
|
|
73
|
-
"axios"
|
|
78
|
+
"crawl"
|
|
74
79
|
];
|
|
75
80
|
function isBot(userAgent, extraBots) {
|
|
76
81
|
const ua = userAgent.toLowerCase();
|
package/dist/next.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/next.ts","../src/index.ts"],"sourcesContent":["/**\n * rankdeploy-middleware/next — Next.js / Vercel middleware\n *\n * Serves pre-rendered HTML with SEO overrides.\n * By default serves to ALL requests (so OG checkers work).\n * Set botsOnly: true to only serve to search engine bots.\n */\n\nimport { isBot, isStaticAsset, isExcluded, fetchPrerendered, RANKDEPLOY_API, type RankDeployOptions } from \"./index\";\n\ninterface NextMiddlewareRequest {\n headers: { get(name: string): string | null };\n nextUrl: { pathname: string; toString(): string };\n}\n\nexport function createMiddleware(options: RankDeployOptions) {\n const apiUrl = options.apiUrl || RANKDEPLOY_API;\n\n return async function middleware(request: NextMiddlewareRequest) {\n const userAgent = request.headers.get(\"user-agent\") || \"\";\n const pathname = request.nextUrl.pathname;\n const hostname = request.nextUrl.hostname || new URL(request.nextUrl.toString()).hostname;\n\n // Serve auto-generated sitemap.xml and robots.txt\n if (pathname === \"/sitemap.xml\" || pathname === \"/robots.txt\") {\n try {\n const file = pathname.slice(1); // \"sitemap.xml\" or \"robots.txt\"\n const res = await fetch(`${apiUrl}/seo-file?domain=${hostname}&file=${file}`);\n if (res.ok) {\n const content = await res.text();\n return new Response(content, {\n status: 200,\n headers: {\n \"Content-Type\": pathname === \"/sitemap.xml\" ? \"application/xml\" : \"text/plain\",\n \"Cache-Control\": \"public, max-age=3600\",\n },\n });\n }\n } catch {\n // Fall through to origin\n }\n return;\n }\n\n // Skip static assets and excluded paths\n if (isStaticAsset(pathname) || isExcluded(pathname, options.excludePaths)) {\n return;\n }\n\n // Only intercept bot requests (default behavior)\n if (options.botsOnly !== false && !isBot(userAgent, options.extraBots)) {\n return;\n }\n\n const html = await fetchPrerendered(request.nextUrl.toString(), userAgent, options.siteKey, options.apiUrl);\n\n if (html) {\n return new Response(html, {\n status: 200,\n headers: {\n \"Content-Type\": \"text/html; charset=utf-8\",\n \"X-Prerendered\": \"true\",\n \"X-Powered-By\": \"Rank Deploy\",\n },\n });\n }\n\n return;\n };\n}\n\nexport const config = {\n matcher: [\"/((?!api|_next/static|_next/image|favicon.ico).*)\"],\n};\n","/**\n * rankdeploy-middleware — Core SEO middleware engine\n *\n * Serves pre-rendered HTML with SEO overrides to all visitors.\n * The pre-rendered HTML is visually identical to the original page\n * but includes injected meta tags (title, description, canonical, og:tags).\n */\n\nexport const RANKDEPLOY_API = \"https://proxy.unikium.com\";\n\nexport const STATIC_EXTENSIONS = /\\.(js|css|png|jpg|jpeg|gif|svg|ico|woff|woff2|ttf|eot|map|json|xml|txt|mp4|webm|pdf|zip)$/i;\n\nexport interface RankDeployOptions {\n /** Your site key from Rank Deploy dashboard (required) */\n siteKey: string;\n /** Rank Deploy API URL. Default: https://proxy.unikium.com */\n apiUrl?: string;\n /** Paths to exclude from pre-rendering */\n excludePaths?: string[];\n /** Only serve to bots (default: false — serves to everyone for OG checker compatibility) */\n botsOnly?: boolean;\n /** Additional bot user agents to detect (used when botsOnly=true) */\n extraBots?: string[];\n}\n\nexport const BOT_USER_AGENTS = [\n \"googlebot\", \"bingbot\", \"yandexbot\", \"duckduckbot\", \"baiduspider\",\n \"slurp\", \"sogou\", \"exabot\",\n \"facebot\", \"facebookexternalhit\", \"twitterbot\", \"linkedinbot\",\n \"whatsapp\", \"telegrambot\", \"applebot\", \"discordbot\", \"slackbot\", \"pinterest\",\n \"screaming frog\", \"ahrefs\", \"semrush\", \"moz.com\", \"rogerbot\", \"dotbot\",\n \"
|
|
1
|
+
{"version":3,"sources":["../src/next.ts","../src/index.ts"],"sourcesContent":["/**\n * rankdeploy-middleware/next — Next.js / Vercel middleware\n *\n * Serves pre-rendered HTML with SEO overrides.\n * By default serves to ALL requests (so OG checkers work).\n * Set botsOnly: true to only serve to search engine bots.\n */\n\nimport { isBot, isStaticAsset, isExcluded, fetchPrerendered, RANKDEPLOY_API, type RankDeployOptions } from \"./index\";\n\ninterface NextMiddlewareRequest {\n headers: { get(name: string): string | null };\n nextUrl: { pathname: string; toString(): string };\n}\n\nexport function createMiddleware(options: RankDeployOptions) {\n const apiUrl = options.apiUrl || RANKDEPLOY_API;\n\n return async function middleware(request: NextMiddlewareRequest) {\n const userAgent = request.headers.get(\"user-agent\") || \"\";\n const pathname = request.nextUrl.pathname;\n const hostname = request.nextUrl.hostname || new URL(request.nextUrl.toString()).hostname;\n\n // Serve auto-generated sitemap.xml and robots.txt\n if (pathname === \"/sitemap.xml\" || pathname === \"/robots.txt\") {\n try {\n const file = pathname.slice(1); // \"sitemap.xml\" or \"robots.txt\"\n const res = await fetch(`${apiUrl}/seo-file?domain=${hostname}&file=${file}`);\n if (res.ok) {\n const content = await res.text();\n return new Response(content, {\n status: 200,\n headers: {\n \"Content-Type\": pathname === \"/sitemap.xml\" ? \"application/xml\" : \"text/plain\",\n \"Cache-Control\": \"public, max-age=3600\",\n },\n });\n }\n } catch {\n // Fall through to origin\n }\n return;\n }\n\n // Skip static assets and excluded paths\n if (isStaticAsset(pathname) || isExcluded(pathname, options.excludePaths)) {\n return;\n }\n\n // Only intercept bot requests (default behavior)\n if (options.botsOnly !== false && !isBot(userAgent, options.extraBots)) {\n return;\n }\n\n const html = await fetchPrerendered(request.nextUrl.toString(), userAgent, options.siteKey, options.apiUrl);\n\n if (html) {\n return new Response(html, {\n status: 200,\n headers: {\n \"Content-Type\": \"text/html; charset=utf-8\",\n \"X-Prerendered\": \"true\",\n \"X-Powered-By\": \"Rank Deploy\",\n },\n });\n }\n\n return;\n };\n}\n\nexport const config = {\n matcher: [\"/((?!api|_next/static|_next/image|favicon.ico).*)\"],\n};\n","/**\n * rankdeploy-middleware — Core SEO middleware engine\n *\n * Serves pre-rendered HTML with SEO overrides to all visitors.\n * The pre-rendered HTML is visually identical to the original page\n * but includes injected meta tags (title, description, canonical, og:tags).\n */\n\nexport const RANKDEPLOY_API = \"https://proxy.unikium.com\";\n\nexport const STATIC_EXTENSIONS = /\\.(js|css|png|jpg|jpeg|gif|svg|ico|woff|woff2|ttf|eot|map|json|xml|txt|mp4|webm|pdf|zip)$/i;\n\nexport interface RankDeployOptions {\n /** Your site key from Rank Deploy dashboard (required) */\n siteKey: string;\n /** Rank Deploy API URL. Default: https://proxy.unikium.com */\n apiUrl?: string;\n /** Paths to exclude from pre-rendering */\n excludePaths?: string[];\n /** Only serve to bots (default: false — serves to everyone for OG checker compatibility) */\n botsOnly?: boolean;\n /** Additional bot user agents to detect (used when botsOnly=true) */\n extraBots?: string[];\n}\n\nexport const BOT_USER_AGENTS = [\n // Search engines\n \"googlebot\", \"bingbot\", \"yandexbot\", \"duckduckbot\", \"baiduspider\",\n \"slurp\", \"sogou\", \"exabot\",\n // Social media crawlers\n \"facebot\", \"facebookexternalhit\", \"twitterbot\", \"linkedinbot\",\n \"whatsapp\", \"telegrambot\", \"applebot\", \"discordbot\", \"slackbot\", \"pinterest\",\n // SEO tools & OG checkers\n \"screaming frog\", \"ahrefs\", \"semrush\", \"moz.com\", \"rogerbot\", \"dotbot\",\n \"opengraphcheck\", \"og-check\", \"metatag\", \"linkpreview\", \"previewbot\",\n \"seobot\", \"seositecheckup\", \"sitecheck\", \"seranking\",\n // AI bots\n \"gptbot\", \"chatgpt\", \"anthropic\", \"claudebot\", \"perplexitybot\", \"cohere\",\n // Generic bot indicators\n \"bot/\", \"spider\", \"crawl\",\n];\n\nexport function isBot(userAgent: string, extraBots?: string[]): boolean {\n const ua = userAgent.toLowerCase();\n const allBots = extraBots ? [...BOT_USER_AGENTS, ...extraBots] : BOT_USER_AGENTS;\n return allBots.some((bot) => ua.includes(bot));\n}\n\nexport function isStaticAsset(pathname: string): boolean {\n return STATIC_EXTENSIONS.test(pathname);\n}\n\nexport function isExcluded(pathname: string, excludePaths?: string[]): boolean {\n if (!excludePaths) return false;\n return excludePaths.some((p) => pathname.startsWith(p));\n}\n\n/**\n * Fetch pre-rendered HTML from Rank Deploy API.\n */\nexport async function fetchPrerendered(\n url: string,\n userAgent: string,\n siteKey: string,\n apiUrl = RANKDEPLOY_API,\n): Promise<string | null> {\n try {\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), 10000);\n\n const res = await fetch(\n `${apiUrl}/render?url=${encodeURIComponent(url)}&key=${encodeURIComponent(siteKey)}`,\n {\n headers: { \"User-Agent\": userAgent || \"Googlebot/2.1\" },\n signal: controller.signal,\n },\n );\n\n clearTimeout(timer);\n\n if (res.status === 200) {\n return res.text();\n }\n return null;\n } catch {\n return null;\n }\n}\n"],"mappings":"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","names":[]}
|
package/dist/next.mjs
CHANGED
package/package.json
CHANGED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["/**\n * rankdeploy-middleware — Core SEO middleware engine\n *\n * Serves pre-rendered HTML with SEO overrides to all visitors.\n * The pre-rendered HTML is visually identical to the original page\n * but includes injected meta tags (title, description, canonical, og:tags).\n */\n\nexport const RANKDEPLOY_API = \"https://proxy.unikium.com\";\n\nexport const STATIC_EXTENSIONS = /\\.(js|css|png|jpg|jpeg|gif|svg|ico|woff|woff2|ttf|eot|map|json|xml|txt|mp4|webm|pdf|zip)$/i;\n\nexport interface RankDeployOptions {\n /** Your site key from Rank Deploy dashboard (required) */\n siteKey: string;\n /** Rank Deploy API URL. Default: https://proxy.unikium.com */\n apiUrl?: string;\n /** Paths to exclude from pre-rendering */\n excludePaths?: string[];\n /** Only serve to bots (default: false — serves to everyone for OG checker compatibility) */\n botsOnly?: boolean;\n /** Additional bot user agents to detect (used when botsOnly=true) */\n extraBots?: string[];\n}\n\nexport const BOT_USER_AGENTS = [\n \"googlebot\", \"bingbot\", \"yandexbot\", \"duckduckbot\", \"baiduspider\",\n \"slurp\", \"sogou\", \"exabot\",\n \"facebot\", \"facebookexternalhit\", \"twitterbot\", \"linkedinbot\",\n \"whatsapp\", \"telegrambot\", \"applebot\", \"discordbot\", \"slackbot\", \"pinterest\",\n \"screaming frog\", \"ahrefs\", \"semrush\", \"moz.com\", \"rogerbot\", \"dotbot\",\n \"gptbot\", \"chatgpt\", \"anthropic\", \"claudebot\", \"perplexitybot\", \"cohere\",\n // SEO tools & OG checkers\n \"opengraph\", \"metatags\", \"preview\", \"crawler\", \"spider\", \"fetch\",\n \"curl\", \"wget\", \"python-requests\", \"node-fetch\", \"axios\",\n];\n\nexport function isBot(userAgent: string, extraBots?: string[]): boolean {\n const ua = userAgent.toLowerCase();\n const allBots = extraBots ? [...BOT_USER_AGENTS, ...extraBots] : BOT_USER_AGENTS;\n return allBots.some((bot) => ua.includes(bot));\n}\n\nexport function isStaticAsset(pathname: string): boolean {\n return STATIC_EXTENSIONS.test(pathname);\n}\n\nexport function isExcluded(pathname: string, excludePaths?: string[]): boolean {\n if (!excludePaths) return false;\n return excludePaths.some((p) => pathname.startsWith(p));\n}\n\n/**\n * Fetch pre-rendered HTML from Rank Deploy API.\n */\nexport async function fetchPrerendered(\n url: string,\n userAgent: string,\n siteKey: string,\n apiUrl = RANKDEPLOY_API,\n): Promise<string | null> {\n try {\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), 10000);\n\n const res = await fetch(\n `${apiUrl}/render?url=${encodeURIComponent(url)}&key=${encodeURIComponent(siteKey)}`,\n {\n headers: { \"User-Agent\": userAgent || \"Googlebot/2.1\" },\n signal: controller.signal,\n },\n );\n\n clearTimeout(timer);\n\n if (res.status === 200) {\n return res.text();\n }\n return null;\n } catch {\n return null;\n }\n}\n"],"mappings":";AAQO,IAAM,iBAAiB;AAEvB,IAAM,oBAAoB;AAe1B,IAAM,kBAAkB;AAAA,EAC7B;AAAA,EAAa;AAAA,EAAW;AAAA,EAAa;AAAA,EAAe;AAAA,EACpD;AAAA,EAAS;AAAA,EAAS;AAAA,EAClB;AAAA,EAAW;AAAA,EAAuB;AAAA,EAAc;AAAA,EAChD;AAAA,EAAY;AAAA,EAAe;AAAA,EAAY;AAAA,EAAc;AAAA,EAAY;AAAA,EACjE;AAAA,EAAkB;AAAA,EAAU;AAAA,EAAW;AAAA,EAAW;AAAA,EAAY;AAAA,EAC9D;AAAA,EAAU;AAAA,EAAW;AAAA,EAAa;AAAA,EAAa;AAAA,EAAiB;AAAA;AAAA,EAEhE;AAAA,EAAa;AAAA,EAAY;AAAA,EAAW;AAAA,EAAW;AAAA,EAAU;AAAA,EACzD;AAAA,EAAQ;AAAA,EAAQ;AAAA,EAAmB;AAAA,EAAc;AACnD;AAEO,SAAS,MAAM,WAAmB,WAA+B;AACtE,QAAM,KAAK,UAAU,YAAY;AACjC,QAAM,UAAU,YAAY,CAAC,GAAG,iBAAiB,GAAG,SAAS,IAAI;AACjE,SAAO,QAAQ,KAAK,CAAC,QAAQ,GAAG,SAAS,GAAG,CAAC;AAC/C;AAEO,SAAS,cAAc,UAA2B;AACvD,SAAO,kBAAkB,KAAK,QAAQ;AACxC;AAEO,SAAS,WAAW,UAAkB,cAAkC;AAC7E,MAAI,CAAC,aAAc,QAAO;AAC1B,SAAO,aAAa,KAAK,CAAC,MAAM,SAAS,WAAW,CAAC,CAAC;AACxD;AAKA,eAAsB,iBACpB,KACA,WACA,SACA,SAAS,gBACe;AACxB,MAAI;AACF,UAAM,aAAa,IAAI,gBAAgB;AACvC,UAAM,QAAQ,WAAW,MAAM,WAAW,MAAM,GAAG,GAAK;AAExD,UAAM,MAAM,MAAM;AAAA,MAChB,GAAG,MAAM,eAAe,mBAAmB,GAAG,CAAC,QAAQ,mBAAmB,OAAO,CAAC;AAAA,MAClF;AAAA,QACE,SAAS,EAAE,cAAc,aAAa,gBAAgB;AAAA,QACtD,QAAQ,WAAW;AAAA,MACrB;AAAA,IACF;AAEA,iBAAa,KAAK;AAElB,QAAI,IAAI,WAAW,KAAK;AACtB,aAAO,IAAI,KAAK;AAAA,IAClB;AACA,WAAO;AAAA,EACT,QAAQ;AACN,WAAO;AAAA,EACT;AACF;","names":[]}
|