rankdeploy-middleware 1.0.0 → 1.1.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.
@@ -45,14 +45,13 @@ function isExcluded(pathname, excludePaths) {
45
45
  if (!excludePaths) return false;
46
46
  return excludePaths.some((p) => pathname.startsWith(p));
47
47
  }
48
- async function fetchPrerendered(url, userAgent, apiUrl = RANKDEPLOY_API) {
48
+ async function fetchPrerendered(url, userAgent, siteKey, apiUrl = RANKDEPLOY_API) {
49
49
  try {
50
50
  const res = await fetch(
51
- `${apiUrl}/render?url=${encodeURIComponent(url)}`,
51
+ `${apiUrl}/render?url=${encodeURIComponent(url)}&key=${encodeURIComponent(siteKey)}`,
52
52
  {
53
53
  headers: { "User-Agent": userAgent },
54
54
  signal: AbortSignal.timeout(1e4)
55
- // 10s timeout
56
55
  }
57
56
  );
58
57
  if (res.status === 200) {
@@ -73,4 +72,4 @@ export {
73
72
  isExcluded,
74
73
  fetchPrerendered
75
74
  };
76
- //# sourceMappingURL=chunk-FPOJYG2E.mjs.map
75
+ //# sourceMappingURL=chunk-UQC64IMV.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts"],"sourcesContent":["/**\n * rankdeploy-middleware — Core SEO middleware engine\n *\n * Detects search engine bots and serves pre-rendered HTML from Rank Deploy API.\n * Human visitors are not affected.\n *\n * Usage:\n * import { createMiddleware } from 'rankdeploy-middleware/next'\n * export const middleware = createMiddleware({ siteKey: 'your-site-key' })\n */\n\nexport const RANKDEPLOY_API = \"https://proxy.unikium.com\";\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];\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 /** Additional bot user agents to detect */\n extraBots?: string[];\n /** Paths to exclude from pre-rendering */\n excludePaths?: string[];\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 res = await fetch(\n `${apiUrl}/render?url=${encodeURIComponent(url)}&key=${encodeURIComponent(siteKey)}`,\n {\n headers: { \"User-Agent\": userAgent },\n signal: AbortSignal.timeout(10_000),\n },\n );\n\n if (res.status === 200) {\n return res.text();\n }\n return null;\n } catch {\n return null;\n }\n}\n"],"mappings":";AAWO,IAAM,iBAAiB;AAEvB,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;AAClE;AAEO,IAAM,oBAAoB;AAa1B,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,MAAM,MAAM;AAAA,MAChB,GAAG,MAAM,eAAe,mBAAmB,GAAG,CAAC,QAAQ,mBAAmB,OAAO,CAAC;AAAA,MAClF;AAAA,QACE,SAAS,EAAE,cAAc,UAAU;AAAA,QACnC,QAAQ,YAAY,QAAQ,GAAM;AAAA,MACpC;AAAA,IACF;AAEA,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
@@ -72,14 +72,13 @@ function isExcluded(pathname, excludePaths) {
72
72
  if (!excludePaths) return false;
73
73
  return excludePaths.some((p) => pathname.startsWith(p));
74
74
  }
75
- async function fetchPrerendered(url, userAgent, apiUrl = RANKDEPLOY_API) {
75
+ async function fetchPrerendered(url, userAgent, siteKey, apiUrl = RANKDEPLOY_API) {
76
76
  try {
77
77
  const res = await fetch(
78
- `${apiUrl}/render?url=${encodeURIComponent(url)}`,
78
+ `${apiUrl}/render?url=${encodeURIComponent(url)}&key=${encodeURIComponent(siteKey)}`,
79
79
  {
80
80
  headers: { "User-Agent": userAgent },
81
81
  signal: AbortSignal.timeout(1e4)
82
- // 10s timeout
83
82
  }
84
83
  );
85
84
  if (res.status === 200) {
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/express.ts","../src/index.ts"],"sourcesContent":["/**\n * @rankdeploy/middleware/express — Express.js middleware\n *\n * Usage:\n * import { rankdeploy } from '@rankdeploy/middleware/express'\n * app.use(rankdeploy())\n *\n * With options:\n * app.use(rankdeploy({ excludePaths: ['/api', '/admin'] }))\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\n/**\n * Create Express middleware for Rank Deploy.\n *\n * Usage:\n * app.use(rankdeploy())\n */\nexport function rankdeploy(options: RankDeployOptions = {}) {\n return async function middleware(\n req: ExpressRequest,\n res: ExpressResponse,\n next: NextFunction,\n ) {\n const userAgent = (req.headers[\"user-agent\"] as string) || req.get?.(\"user-agent\") || \"\";\n const pathname = req.url.split(\"?\")[0];\n\n if (!isBot(userAgent, options.extraBots)) {\n return next();\n }\n\n if (isStaticAsset(pathname)) {\n return next();\n }\n\n if (isExcluded(pathname, options.excludePaths)) {\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.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 * Detects search engine bots and serves pre-rendered HTML from Rank Deploy API.\n * Human visitors are not affected.\n *\n * Usage:\n * import { middleware } from '@rankdeploy/middleware/next' // Next.js\n * import { default } from '@rankdeploy/middleware/netlify' // Netlify\n * import { rankdeploy } from '@rankdeploy/middleware/express' // Express\n */\n\nexport const RANKDEPLOY_API = \"https://proxy.unikium.com\";\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];\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 /** Rank Deploy API URL. Default: https://proxy.unikium.com */\n apiUrl?: string;\n /** Additional bot user agents to detect */\n extraBots?: string[];\n /** Paths to exclude from pre-rendering */\n excludePaths?: string[];\n}\n\n/**\n * Check if a user agent string belongs to a bot.\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\n/**\n * Check if a path is a static asset.\n */\nexport function isStaticAsset(pathname: string): boolean {\n return STATIC_EXTENSIONS.test(pathname);\n}\n\n/**\n * Check if a path should be excluded.\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 * Returns the HTML string if available, null otherwise.\n */\nexport async function fetchPrerendered(\n url: string,\n userAgent: string,\n apiUrl = RANKDEPLOY_API,\n): Promise<string | null> {\n try {\n const res = await fetch(\n `${apiUrl}/render?url=${encodeURIComponent(url)}`,\n {\n headers: { \"User-Agent\": userAgent },\n signal: AbortSignal.timeout(10_000), // 10s timeout\n },\n );\n\n if (res.status === 200) {\n return res.text();\n }\n\n // 204 = passthrough (no cache), anything else = error\n return null;\n } catch {\n // Network error, timeout — fail silently\n return null;\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACYO,IAAM,iBAAiB;AAEvB,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;AAClE;AAEO,IAAM,oBAAoB;AAc1B,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;AAKO,SAAS,cAAc,UAA2B;AACvD,SAAO,kBAAkB,KAAK,QAAQ;AACxC;AAKO,SAAS,WAAW,UAAkB,cAAkC;AAC7E,MAAI,CAAC,aAAc,QAAO;AAC1B,SAAO,aAAa,KAAK,CAAC,MAAM,SAAS,WAAW,CAAC,CAAC;AACxD;AAMA,eAAsB,iBACpB,KACA,WACA,SAAS,gBACe;AACxB,MAAI;AACF,UAAM,MAAM,MAAM;AAAA,MAChB,GAAG,MAAM,eAAe,mBAAmB,GAAG,CAAC;AAAA,MAC/C;AAAA,QACE,SAAS,EAAE,cAAc,UAAU;AAAA,QACnC,QAAQ,YAAY,QAAQ,GAAM;AAAA;AAAA,MACpC;AAAA,IACF;AAEA,QAAI,IAAI,WAAW,KAAK;AACtB,aAAO,IAAI,KAAK;AAAA,IAClB;AAGA,WAAO;AAAA,EACT,QAAQ;AAEN,WAAO;AAAA,EACT;AACF;;;ADpDO,SAAS,WAAW,UAA6B,CAAC,GAAG;AAC1D,SAAO,eAAe,WACpB,KACA,KACA,MACA;AACA,UAAM,YAAa,IAAI,QAAQ,YAAY,KAAgB,IAAI,MAAM,YAAY,KAAK;AACtF,UAAM,WAAW,IAAI,IAAI,MAAM,GAAG,EAAE,CAAC;AAErC,QAAI,CAAC,MAAM,WAAW,QAAQ,SAAS,GAAG;AACxC,aAAO,KAAK;AAAA,IACd;AAEA,QAAI,cAAc,QAAQ,GAAG;AAC3B,aAAO,KAAK;AAAA,IACd;AAEA,QAAI,WAAW,UAAU,QAAQ,YAAY,GAAG;AAC9C,aAAO,KAAK;AAAA,IACd;AAEA,UAAM,WAAW,IAAI,YAAY;AACjC,UAAM,OAAO,IAAI,MAAM,MAAM,KAAK,IAAI,QAAQ,QAAQ;AACtD,UAAM,UAAU,GAAG,QAAQ,MAAM,IAAI,GAAG,IAAI,GAAG;AAE/C,UAAM,OAAO,MAAM,iBAAiB,SAAS,WAAW,QAAQ,MAAM;AAEtE,QAAI,MAAM;AACR,UAAI,IAAI,gBAAgB,0BAA0B;AAClD,UAAI,IAAI,iBAAiB,MAAM;AAC/B,UAAI,IAAI,gBAAgB,aAAa;AACrC,aAAO,IAAI,OAAO,GAAG,EAAE,KAAK,IAAI;AAAA,IAClC;AAEA,SAAK;AAAA,EACP;AACF;AAEA,IAAO,kBAAQ;","names":[]}
1
+ {"version":3,"sources":["../src/express.ts","../src/index.ts"],"sourcesContent":["/**\n * @rankdeploy/middleware/express — Express.js middleware\n *\n * Usage:\n * import { rankdeploy } from '@rankdeploy/middleware/express'\n * app.use(rankdeploy())\n *\n * With options:\n * app.use(rankdeploy({ excludePaths: ['/api', '/admin'] }))\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\n/**\n * Create Express middleware for Rank Deploy.\n *\n * Usage:\n * app.use(rankdeploy())\n */\nexport function rankdeploy(options: RankDeployOptions = {}) {\n return async function middleware(\n req: ExpressRequest,\n res: ExpressResponse,\n next: NextFunction,\n ) {\n const userAgent = (req.headers[\"user-agent\"] as string) || req.get?.(\"user-agent\") || \"\";\n const pathname = req.url.split(\"?\")[0];\n\n if (!isBot(userAgent, options.extraBots)) {\n return next();\n }\n\n if (isStaticAsset(pathname)) {\n return next();\n }\n\n if (isExcluded(pathname, options.excludePaths)) {\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.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 * Detects search engine bots and serves pre-rendered HTML from Rank Deploy API.\n * Human visitors are not affected.\n *\n * Usage:\n * import { createMiddleware } from 'rankdeploy-middleware/next'\n * export const middleware = createMiddleware({ siteKey: 'your-site-key' })\n */\n\nexport const RANKDEPLOY_API = \"https://proxy.unikium.com\";\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];\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 /** Additional bot user agents to detect */\n extraBots?: string[];\n /** Paths to exclude from pre-rendering */\n excludePaths?: string[];\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 res = await fetch(\n `${apiUrl}/render?url=${encodeURIComponent(url)}&key=${encodeURIComponent(siteKey)}`,\n {\n headers: { \"User-Agent\": userAgent },\n signal: AbortSignal.timeout(10_000),\n },\n );\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;;;ACWO,IAAM,iBAAiB;AAEvB,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;AAClE;AAEO,IAAM,oBAAoB;AAa1B,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,MAAM,MAAM;AAAA,MAChB,GAAG,MAAM,eAAe,mBAAmB,GAAG,CAAC,QAAQ,mBAAmB,OAAO,CAAC;AAAA,MAClF;AAAA,QACE,SAAS,EAAE,cAAc,UAAU;AAAA,QACnC,QAAQ,YAAY,QAAQ,GAAM;AAAA,MACpC;AAAA,IACF;AAEA,QAAI,IAAI,WAAW,KAAK;AACtB,aAAO,IAAI,KAAK;AAAA,IAClB;AACA,WAAO;AAAA,EACT,QAAQ;AACN,WAAO;AAAA,EACT;AACF;;;ADzCO,SAAS,WAAW,UAA6B,CAAC,GAAG;AAC1D,SAAO,eAAe,WACpB,KACA,KACA,MACA;AACA,UAAM,YAAa,IAAI,QAAQ,YAAY,KAAgB,IAAI,MAAM,YAAY,KAAK;AACtF,UAAM,WAAW,IAAI,IAAI,MAAM,GAAG,EAAE,CAAC;AAErC,QAAI,CAAC,MAAM,WAAW,QAAQ,SAAS,GAAG;AACxC,aAAO,KAAK;AAAA,IACd;AAEA,QAAI,cAAc,QAAQ,GAAG;AAC3B,aAAO,KAAK;AAAA,IACd;AAEA,QAAI,WAAW,UAAU,QAAQ,YAAY,GAAG;AAC9C,aAAO,KAAK;AAAA,IACd;AAEA,UAAM,WAAW,IAAI,YAAY;AACjC,UAAM,OAAO,IAAI,MAAM,MAAM,KAAK,IAAI,QAAQ,QAAQ;AACtD,UAAM,UAAU,GAAG,QAAQ,MAAM,IAAI,GAAG,IAAI,GAAG;AAE/C,UAAM,OAAO,MAAM,iBAAiB,SAAS,WAAW,QAAQ,MAAM;AAEtE,QAAI,MAAM;AACR,UAAI,IAAI,gBAAgB,0BAA0B;AAClD,UAAI,IAAI,iBAAiB,MAAM;AAC/B,UAAI,IAAI,gBAAgB,aAAa;AACrC,aAAO,IAAI,OAAO,GAAG,EAAE,KAAK,IAAI;AAAA,IAClC;AAEA,SAAK;AAAA,EACP;AACF;AAEA,IAAO,kBAAQ;","names":[]}
package/dist/express.mjs CHANGED
@@ -3,7 +3,7 @@ import {
3
3
  isBot,
4
4
  isExcluded,
5
5
  isStaticAsset
6
- } from "./chunk-FPOJYG2E.mjs";
6
+ } from "./chunk-UQC64IMV.mjs";
7
7
 
8
8
  // src/express.ts
9
9
  function rankdeploy(options = {}) {
package/dist/index.js CHANGED
@@ -75,14 +75,13 @@ function isExcluded(pathname, excludePaths) {
75
75
  if (!excludePaths) return false;
76
76
  return excludePaths.some((p) => pathname.startsWith(p));
77
77
  }
78
- async function fetchPrerendered(url, userAgent, apiUrl = RANKDEPLOY_API) {
78
+ async function fetchPrerendered(url, userAgent, siteKey, apiUrl = RANKDEPLOY_API) {
79
79
  try {
80
80
  const res = await fetch(
81
- `${apiUrl}/render?url=${encodeURIComponent(url)}`,
81
+ `${apiUrl}/render?url=${encodeURIComponent(url)}&key=${encodeURIComponent(siteKey)}`,
82
82
  {
83
83
  headers: { "User-Agent": userAgent },
84
84
  signal: AbortSignal.timeout(1e4)
85
- // 10s timeout
86
85
  }
87
86
  );
88
87
  if (res.status === 200) {
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 * Detects search engine bots and serves pre-rendered HTML from Rank Deploy API.\n * Human visitors are not affected.\n *\n * Usage:\n * import { middleware } from '@rankdeploy/middleware/next' // Next.js\n * import { default } from '@rankdeploy/middleware/netlify' // Netlify\n * import { rankdeploy } from '@rankdeploy/middleware/express' // Express\n */\n\nexport const RANKDEPLOY_API = \"https://proxy.unikium.com\";\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];\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 /** Rank Deploy API URL. Default: https://proxy.unikium.com */\n apiUrl?: string;\n /** Additional bot user agents to detect */\n extraBots?: string[];\n /** Paths to exclude from pre-rendering */\n excludePaths?: string[];\n}\n\n/**\n * Check if a user agent string belongs to a bot.\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\n/**\n * Check if a path is a static asset.\n */\nexport function isStaticAsset(pathname: string): boolean {\n return STATIC_EXTENSIONS.test(pathname);\n}\n\n/**\n * Check if a path should be excluded.\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 * Returns the HTML string if available, null otherwise.\n */\nexport async function fetchPrerendered(\n url: string,\n userAgent: string,\n apiUrl = RANKDEPLOY_API,\n): Promise<string | null> {\n try {\n const res = await fetch(\n `${apiUrl}/render?url=${encodeURIComponent(url)}`,\n {\n headers: { \"User-Agent\": userAgent },\n signal: AbortSignal.timeout(10_000), // 10s timeout\n },\n );\n\n if (res.status === 200) {\n return res.text();\n }\n\n // 204 = passthrough (no cache), anything else = error\n return null;\n } catch {\n // Network error, timeout — fail silently\n return null;\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAYO,IAAM,iBAAiB;AAEvB,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;AAClE;AAEO,IAAM,oBAAoB;AAc1B,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;AAKO,SAAS,cAAc,UAA2B;AACvD,SAAO,kBAAkB,KAAK,QAAQ;AACxC;AAKO,SAAS,WAAW,UAAkB,cAAkC;AAC7E,MAAI,CAAC,aAAc,QAAO;AAC1B,SAAO,aAAa,KAAK,CAAC,MAAM,SAAS,WAAW,CAAC,CAAC;AACxD;AAMA,eAAsB,iBACpB,KACA,WACA,SAAS,gBACe;AACxB,MAAI;AACF,UAAM,MAAM,MAAM;AAAA,MAChB,GAAG,MAAM,eAAe,mBAAmB,GAAG,CAAC;AAAA,MAC/C;AAAA,QACE,SAAS,EAAE,cAAc,UAAU;AAAA,QACnC,QAAQ,YAAY,QAAQ,GAAM;AAAA;AAAA,MACpC;AAAA,IACF;AAEA,QAAI,IAAI,WAAW,KAAK;AACtB,aAAO,IAAI,KAAK;AAAA,IAClB;AAGA,WAAO;AAAA,EACT,QAAQ;AAEN,WAAO;AAAA,EACT;AACF;","names":[]}
1
+ {"version":3,"sources":["../src/index.ts"],"sourcesContent":["/**\n * rankdeploy-middleware — Core SEO middleware engine\n *\n * Detects search engine bots and serves pre-rendered HTML from Rank Deploy API.\n * Human visitors are not affected.\n *\n * Usage:\n * import { createMiddleware } from 'rankdeploy-middleware/next'\n * export const middleware = createMiddleware({ siteKey: 'your-site-key' })\n */\n\nexport const RANKDEPLOY_API = \"https://proxy.unikium.com\";\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];\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 /** Additional bot user agents to detect */\n extraBots?: string[];\n /** Paths to exclude from pre-rendering */\n excludePaths?: string[];\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 res = await fetch(\n `${apiUrl}/render?url=${encodeURIComponent(url)}&key=${encodeURIComponent(siteKey)}`,\n {\n headers: { \"User-Agent\": userAgent },\n signal: AbortSignal.timeout(10_000),\n },\n );\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;AAWO,IAAM,iBAAiB;AAEvB,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;AAClE;AAEO,IAAM,oBAAoB;AAa1B,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,MAAM,MAAM;AAAA,MAChB,GAAG,MAAM,eAAe,mBAAmB,GAAG,CAAC,QAAQ,mBAAmB,OAAO,CAAC;AAAA,MAClF;AAAA,QACE,SAAS,EAAE,cAAc,UAAU;AAAA,QACnC,QAAQ,YAAY,QAAQ,GAAM;AAAA,MACpC;AAAA,IACF;AAEA,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
@@ -6,7 +6,7 @@ import {
6
6
  isBot,
7
7
  isExcluded,
8
8
  isStaticAsset
9
- } from "./chunk-FPOJYG2E.mjs";
9
+ } from "./chunk-UQC64IMV.mjs";
10
10
  export {
11
11
  BOT_USER_AGENTS,
12
12
  RANKDEPLOY_API,
package/dist/netlify.js CHANGED
@@ -72,14 +72,13 @@ function isExcluded(pathname, excludePaths) {
72
72
  if (!excludePaths) return false;
73
73
  return excludePaths.some((p) => pathname.startsWith(p));
74
74
  }
75
- async function fetchPrerendered(url, userAgent, apiUrl = RANKDEPLOY_API) {
75
+ async function fetchPrerendered(url, userAgent, siteKey, apiUrl = RANKDEPLOY_API) {
76
76
  try {
77
77
  const res = await fetch(
78
- `${apiUrl}/render?url=${encodeURIComponent(url)}`,
78
+ `${apiUrl}/render?url=${encodeURIComponent(url)}&key=${encodeURIComponent(siteKey)}`,
79
79
  {
80
80
  headers: { "User-Agent": userAgent },
81
81
  signal: AbortSignal.timeout(1e4)
82
- // 10s timeout
83
82
  }
84
83
  );
85
84
  if (res.status === 200) {
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/netlify.ts","../src/index.ts"],"sourcesContent":["/**\n * @rankdeploy/middleware/netlify — Netlify Edge Function middleware\n *\n * Usage in netlify/edge-functions/rankdeploy.ts:\n * export { default } from '@rankdeploy/middleware/netlify'\n *\n * Add to netlify.toml:\n * [[edge_functions]]\n * function = \"rankdeploy\"\n * path = \"/*\"\n */\n\nimport { isBot, isStaticAsset, isExcluded, fetchPrerendered, type RankDeployOptions } from \"./index\";\n\ninterface NetlifyContext {\n next(): Promise<Response>;\n}\n\n/**\n * Create a Netlify Edge Function handler with custom options.\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 (!isBot(userAgent, options.extraBots)) {\n return context.next();\n }\n\n if (isStaticAsset(pathname)) {\n return context.next();\n }\n\n if (isExcluded(pathname, options.excludePaths)) {\n return context.next();\n }\n\n const html = await fetchPrerendered(request.url, userAgent, 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/**\n * Default handler — ready to use as-is.\n */\nexport default createHandler();\n","/**\n * @rankdeploy/middleware — Core SEO middleware engine\n *\n * Detects search engine bots and serves pre-rendered HTML from Rank Deploy API.\n * Human visitors are not affected.\n *\n * Usage:\n * import { middleware } from '@rankdeploy/middleware/next' // Next.js\n * import { default } from '@rankdeploy/middleware/netlify' // Netlify\n * import { rankdeploy } from '@rankdeploy/middleware/express' // Express\n */\n\nexport const RANKDEPLOY_API = \"https://proxy.unikium.com\";\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];\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 /** Rank Deploy API URL. Default: https://proxy.unikium.com */\n apiUrl?: string;\n /** Additional bot user agents to detect */\n extraBots?: string[];\n /** Paths to exclude from pre-rendering */\n excludePaths?: string[];\n}\n\n/**\n * Check if a user agent string belongs to a bot.\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\n/**\n * Check if a path is a static asset.\n */\nexport function isStaticAsset(pathname: string): boolean {\n return STATIC_EXTENSIONS.test(pathname);\n}\n\n/**\n * Check if a path should be excluded.\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 * Returns the HTML string if available, null otherwise.\n */\nexport async function fetchPrerendered(\n url: string,\n userAgent: string,\n apiUrl = RANKDEPLOY_API,\n): Promise<string | null> {\n try {\n const res = await fetch(\n `${apiUrl}/render?url=${encodeURIComponent(url)}`,\n {\n headers: { \"User-Agent\": userAgent },\n signal: AbortSignal.timeout(10_000), // 10s timeout\n },\n );\n\n if (res.status === 200) {\n return res.text();\n }\n\n // 204 = passthrough (no cache), anything else = error\n return null;\n } catch {\n // Network error, timeout — fail silently\n return null;\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACYO,IAAM,iBAAiB;AAEvB,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;AAClE;AAEO,IAAM,oBAAoB;AAc1B,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;AAKO,SAAS,cAAc,UAA2B;AACvD,SAAO,kBAAkB,KAAK,QAAQ;AACxC;AAKO,SAAS,WAAW,UAAkB,cAAkC;AAC7E,MAAI,CAAC,aAAc,QAAO;AAC1B,SAAO,aAAa,KAAK,CAAC,MAAM,SAAS,WAAW,CAAC,CAAC;AACxD;AAMA,eAAsB,iBACpB,KACA,WACA,SAAS,gBACe;AACxB,MAAI;AACF,UAAM,MAAM,MAAM;AAAA,MAChB,GAAG,MAAM,eAAe,mBAAmB,GAAG,CAAC;AAAA,MAC/C;AAAA,QACE,SAAS,EAAE,cAAc,UAAU;AAAA,QACnC,QAAQ,YAAY,QAAQ,GAAM;AAAA;AAAA,MACpC;AAAA,IACF;AAEA,QAAI,IAAI,WAAW,KAAK;AACtB,aAAO,IAAI,KAAK;AAAA,IAClB;AAGA,WAAO;AAAA,EACT,QAAQ;AAEN,WAAO;AAAA,EACT;AACF;;;ADjEO,SAAS,cAAc,UAA6B,CAAC,GAAG;AAC7D,SAAO,eAAe,QAAQ,SAAkB,SAAyB;AACvE,UAAM,YAAY,QAAQ,QAAQ,IAAI,YAAY,KAAK;AACvD,UAAM,WAAW,IAAI,IAAI,QAAQ,GAAG,EAAE;AAEtC,QAAI,CAAC,MAAM,WAAW,QAAQ,SAAS,GAAG;AACxC,aAAO,QAAQ,KAAK;AAAA,IACtB;AAEA,QAAI,cAAc,QAAQ,GAAG;AAC3B,aAAO,QAAQ,KAAK;AAAA,IACtB;AAEA,QAAI,WAAW,UAAU,QAAQ,YAAY,GAAG;AAC9C,aAAO,QAAQ,KAAK;AAAA,IACtB;AAEA,UAAM,OAAO,MAAM,iBAAiB,QAAQ,KAAK,WAAW,QAAQ,MAAM;AAE1E,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;AAKA,IAAO,kBAAQ,cAAc;","names":[]}
1
+ {"version":3,"sources":["../src/netlify.ts","../src/index.ts"],"sourcesContent":["/**\n * @rankdeploy/middleware/netlify — Netlify Edge Function middleware\n *\n * Usage in netlify/edge-functions/rankdeploy.ts:\n * export { default } from '@rankdeploy/middleware/netlify'\n *\n * Add to netlify.toml:\n * [[edge_functions]]\n * function = \"rankdeploy\"\n * path = \"/*\"\n */\n\nimport { isBot, isStaticAsset, isExcluded, fetchPrerendered, type RankDeployOptions } from \"./index\";\n\ninterface NetlifyContext {\n next(): Promise<Response>;\n}\n\n/**\n * Create a Netlify Edge Function handler with custom options.\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 (!isBot(userAgent, options.extraBots)) {\n return context.next();\n }\n\n if (isStaticAsset(pathname)) {\n return context.next();\n }\n\n if (isExcluded(pathname, options.excludePaths)) {\n return context.next();\n }\n\n const html = await fetchPrerendered(request.url, userAgent, 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/**\n * Default handler — ready to use as-is.\n */\nexport default createHandler();\n","/**\n * rankdeploy-middleware — Core SEO middleware engine\n *\n * Detects search engine bots and serves pre-rendered HTML from Rank Deploy API.\n * Human visitors are not affected.\n *\n * Usage:\n * import { createMiddleware } from 'rankdeploy-middleware/next'\n * export const middleware = createMiddleware({ siteKey: 'your-site-key' })\n */\n\nexport const RANKDEPLOY_API = \"https://proxy.unikium.com\";\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];\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 /** Additional bot user agents to detect */\n extraBots?: string[];\n /** Paths to exclude from pre-rendering */\n excludePaths?: string[];\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 res = await fetch(\n `${apiUrl}/render?url=${encodeURIComponent(url)}&key=${encodeURIComponent(siteKey)}`,\n {\n headers: { \"User-Agent\": userAgent },\n signal: AbortSignal.timeout(10_000),\n },\n );\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;;;ACWO,IAAM,iBAAiB;AAEvB,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;AAClE;AAEO,IAAM,oBAAoB;AAa1B,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,MAAM,MAAM;AAAA,MAChB,GAAG,MAAM,eAAe,mBAAmB,GAAG,CAAC,QAAQ,mBAAmB,OAAO,CAAC;AAAA,MAClF;AAAA,QACE,SAAS,EAAE,cAAc,UAAU;AAAA,QACnC,QAAQ,YAAY,QAAQ,GAAM;AAAA,MACpC;AAAA,IACF;AAEA,QAAI,IAAI,WAAW,KAAK;AACtB,aAAO,IAAI,KAAK;AAAA,IAClB;AACA,WAAO;AAAA,EACT,QAAQ;AACN,WAAO;AAAA,EACT;AACF;;;ADtDO,SAAS,cAAc,UAA6B,CAAC,GAAG;AAC7D,SAAO,eAAe,QAAQ,SAAkB,SAAyB;AACvE,UAAM,YAAY,QAAQ,QAAQ,IAAI,YAAY,KAAK;AACvD,UAAM,WAAW,IAAI,IAAI,QAAQ,GAAG,EAAE;AAEtC,QAAI,CAAC,MAAM,WAAW,QAAQ,SAAS,GAAG;AACxC,aAAO,QAAQ,KAAK;AAAA,IACtB;AAEA,QAAI,cAAc,QAAQ,GAAG;AAC3B,aAAO,QAAQ,KAAK;AAAA,IACtB;AAEA,QAAI,WAAW,UAAU,QAAQ,YAAY,GAAG;AAC9C,aAAO,QAAQ,KAAK;AAAA,IACtB;AAEA,UAAM,OAAO,MAAM,iBAAiB,QAAQ,KAAK,WAAW,QAAQ,MAAM;AAE1E,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;AAKA,IAAO,kBAAQ,cAAc;","names":[]}
package/dist/netlify.mjs CHANGED
@@ -3,7 +3,7 @@ import {
3
3
  isBot,
4
4
  isExcluded,
5
5
  isStaticAsset
6
- } from "./chunk-FPOJYG2E.mjs";
6
+ } from "./chunk-UQC64IMV.mjs";
7
7
 
8
8
  // src/netlify.ts
9
9
  function createHandler(options = {}) {
package/dist/next.js CHANGED
@@ -21,8 +21,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
21
21
  var next_exports = {};
22
22
  __export(next_exports, {
23
23
  config: () => config,
24
- createMiddleware: () => createMiddleware,
25
- middleware: () => middleware
24
+ createMiddleware: () => createMiddleware
26
25
  });
27
26
  module.exports = __toCommonJS(next_exports);
28
27
 
@@ -73,14 +72,13 @@ function isExcluded(pathname, excludePaths) {
73
72
  if (!excludePaths) return false;
74
73
  return excludePaths.some((p) => pathname.startsWith(p));
75
74
  }
76
- async function fetchPrerendered(url, userAgent, apiUrl = RANKDEPLOY_API) {
75
+ async function fetchPrerendered(url, userAgent, siteKey, apiUrl = RANKDEPLOY_API) {
77
76
  try {
78
77
  const res = await fetch(
79
- `${apiUrl}/render?url=${encodeURIComponent(url)}`,
78
+ `${apiUrl}/render?url=${encodeURIComponent(url)}&key=${encodeURIComponent(siteKey)}`,
80
79
  {
81
80
  headers: { "User-Agent": userAgent },
82
81
  signal: AbortSignal.timeout(1e4)
83
- // 10s timeout
84
82
  }
85
83
  );
86
84
  if (res.status === 200) {
@@ -93,14 +91,14 @@ async function fetchPrerendered(url, userAgent, apiUrl = RANKDEPLOY_API) {
93
91
  }
94
92
 
95
93
  // src/next.ts
96
- function createMiddleware(options = {}) {
97
- return async function middleware2(request) {
94
+ function createMiddleware(options) {
95
+ return async function middleware(request) {
98
96
  const userAgent = request.headers.get("user-agent") || "";
99
97
  const pathname = request.nextUrl.pathname;
100
98
  if (!isBot(userAgent, options.extraBots) || isStaticAsset(pathname) || isExcluded(pathname, options.excludePaths)) {
101
99
  return;
102
100
  }
103
- const html = await fetchPrerendered(request.nextUrl.toString(), userAgent, options.apiUrl);
101
+ const html = await fetchPrerendered(request.nextUrl.toString(), userAgent, options.siteKey, options.apiUrl);
104
102
  if (html) {
105
103
  return new Response(html, {
106
104
  status: 200,
@@ -114,14 +112,12 @@ function createMiddleware(options = {}) {
114
112
  return;
115
113
  };
116
114
  }
117
- var middleware = createMiddleware();
118
115
  var config = {
119
116
  matcher: ["/((?!api|_next/static|_next/image|favicon.ico).*)"]
120
117
  };
121
118
  // Annotate the CommonJS export names for ESM import in node:
122
119
  0 && (module.exports = {
123
120
  config,
124
- createMiddleware,
125
- middleware
121
+ createMiddleware
126
122
  });
127
123
  //# sourceMappingURL=next.js.map
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 * Usage in middleware.ts:\n * export { middleware, config } from '@rankdeploy/middleware/next'\n */\n\nimport { isBot, isStaticAsset, isExcluded, fetchPrerendered, type RankDeployOptions } from \"./index\";\n\ninterface NextMiddlewareRequest {\n headers: { get(name: string): string | null };\n nextUrl: { pathname: string; toString(): string };\n}\n\n/**\n * Create a Next.js middleware function with custom options.\n */\nexport function createMiddleware(options: RankDeployOptions = {}) {\n return async function middleware(request: NextMiddlewareRequest) {\n const userAgent = request.headers.get(\"user-agent\") || \"\";\n const pathname = request.nextUrl.pathname;\n\n // Skip non-bot, static assets, excluded paths\n if (!isBot(userAgent, options.extraBots) || isStaticAsset(pathname) || isExcluded(pathname, options.excludePaths)) {\n return; // undefined = next() in Next.js middleware\n }\n\n const html = await fetchPrerendered(request.nextUrl.toString(), userAgent, 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 // No pre-rendered version — let Next.js handle normally\n return;\n };\n}\n\n/**\n * Default middleware — ready to use.\n */\nexport const middleware = createMiddleware();\n\nexport const config = {\n matcher: [\"/((?!api|_next/static|_next/image|favicon.ico).*)\"],\n};\n","/**\n * @rankdeploy/middleware — Core SEO middleware engine\n *\n * Detects search engine bots and serves pre-rendered HTML from Rank Deploy API.\n * Human visitors are not affected.\n *\n * Usage:\n * import { middleware } from '@rankdeploy/middleware/next' // Next.js\n * import { default } from '@rankdeploy/middleware/netlify' // Netlify\n * import { rankdeploy } from '@rankdeploy/middleware/express' // Express\n */\n\nexport const RANKDEPLOY_API = \"https://proxy.unikium.com\";\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];\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 /** Rank Deploy API URL. Default: https://proxy.unikium.com */\n apiUrl?: string;\n /** Additional bot user agents to detect */\n extraBots?: string[];\n /** Paths to exclude from pre-rendering */\n excludePaths?: string[];\n}\n\n/**\n * Check if a user agent string belongs to a bot.\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\n/**\n * Check if a path is a static asset.\n */\nexport function isStaticAsset(pathname: string): boolean {\n return STATIC_EXTENSIONS.test(pathname);\n}\n\n/**\n * Check if a path should be excluded.\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 * Returns the HTML string if available, null otherwise.\n */\nexport async function fetchPrerendered(\n url: string,\n userAgent: string,\n apiUrl = RANKDEPLOY_API,\n): Promise<string | null> {\n try {\n const res = await fetch(\n `${apiUrl}/render?url=${encodeURIComponent(url)}`,\n {\n headers: { \"User-Agent\": userAgent },\n signal: AbortSignal.timeout(10_000), // 10s timeout\n },\n );\n\n if (res.status === 200) {\n return res.text();\n }\n\n // 204 = passthrough (no cache), anything else = error\n return null;\n } catch {\n // Network error, timeout — fail silently\n return null;\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACYO,IAAM,iBAAiB;AAEvB,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;AAClE;AAEO,IAAM,oBAAoB;AAc1B,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;AAKO,SAAS,cAAc,UAA2B;AACvD,SAAO,kBAAkB,KAAK,QAAQ;AACxC;AAKO,SAAS,WAAW,UAAkB,cAAkC;AAC7E,MAAI,CAAC,aAAc,QAAO;AAC1B,SAAO,aAAa,KAAK,CAAC,MAAM,SAAS,WAAW,CAAC,CAAC;AACxD;AAMA,eAAsB,iBACpB,KACA,WACA,SAAS,gBACe;AACxB,MAAI;AACF,UAAM,MAAM,MAAM;AAAA,MAChB,GAAG,MAAM,eAAe,mBAAmB,GAAG,CAAC;AAAA,MAC/C;AAAA,QACE,SAAS,EAAE,cAAc,UAAU;AAAA,QACnC,QAAQ,YAAY,QAAQ,GAAM;AAAA;AAAA,MACpC;AAAA,IACF;AAEA,QAAI,IAAI,WAAW,KAAK;AACtB,aAAO,IAAI,KAAK;AAAA,IAClB;AAGA,WAAO;AAAA,EACT,QAAQ;AAEN,WAAO;AAAA,EACT;AACF;;;ADrEO,SAAS,iBAAiB,UAA6B,CAAC,GAAG;AAChE,SAAO,eAAeA,YAAW,SAAgC;AAC/D,UAAM,YAAY,QAAQ,QAAQ,IAAI,YAAY,KAAK;AACvD,UAAM,WAAW,QAAQ,QAAQ;AAGjC,QAAI,CAAC,MAAM,WAAW,QAAQ,SAAS,KAAK,cAAc,QAAQ,KAAK,WAAW,UAAU,QAAQ,YAAY,GAAG;AACjH;AAAA,IACF;AAEA,UAAM,OAAO,MAAM,iBAAiB,QAAQ,QAAQ,SAAS,GAAG,WAAW,QAAQ,MAAM;AAEzF,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;AAGA;AAAA,EACF;AACF;AAKO,IAAM,aAAa,iBAAiB;AAEpC,IAAM,SAAS;AAAA,EACpB,SAAS,CAAC,mDAAmD;AAC/D;","names":["middleware"]}
1
+ {"version":3,"sources":["../src/next.ts","../src/index.ts"],"sourcesContent":["/**\n * rankdeploy-middleware/next — Next.js / Vercel middleware\n *\n * Usage:\n * import { createMiddleware } from 'rankdeploy-middleware/next'\n * export const middleware = createMiddleware({ siteKey: 'your-site-key' })\n * export const config = { matcher: ['/((?!api|_next/static|_next/image|favicon.ico).*)'] }\n */\n\nimport { isBot, isStaticAsset, isExcluded, fetchPrerendered, 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 return async function middleware(request: NextMiddlewareRequest) {\n const userAgent = request.headers.get(\"user-agent\") || \"\";\n const pathname = request.nextUrl.pathname;\n\n if (!isBot(userAgent, options.extraBots) || isStaticAsset(pathname) || isExcluded(pathname, options.excludePaths)) {\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 * Detects search engine bots and serves pre-rendered HTML from Rank Deploy API.\n * Human visitors are not affected.\n *\n * Usage:\n * import { createMiddleware } from 'rankdeploy-middleware/next'\n * export const middleware = createMiddleware({ siteKey: 'your-site-key' })\n */\n\nexport const RANKDEPLOY_API = \"https://proxy.unikium.com\";\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];\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 /** Additional bot user agents to detect */\n extraBots?: string[];\n /** Paths to exclude from pre-rendering */\n excludePaths?: string[];\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 res = await fetch(\n `${apiUrl}/render?url=${encodeURIComponent(url)}&key=${encodeURIComponent(siteKey)}`,\n {\n headers: { \"User-Agent\": userAgent },\n signal: AbortSignal.timeout(10_000),\n },\n );\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;;;ACWO,IAAM,iBAAiB;AAEvB,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;AAClE;AAEO,IAAM,oBAAoB;AAa1B,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,MAAM,MAAM;AAAA,MAChB,GAAG,MAAM,eAAe,mBAAmB,GAAG,CAAC,QAAQ,mBAAmB,OAAO,CAAC;AAAA,MAClF;AAAA,QACE,SAAS,EAAE,cAAc,UAAU;AAAA,QACnC,QAAQ,YAAY,QAAQ,GAAM;AAAA,MACpC;AAAA,IACF;AAEA,QAAI,IAAI,WAAW,KAAK;AACtB,aAAO,IAAI,KAAK;AAAA,IAClB;AACA,WAAO;AAAA,EACT,QAAQ;AACN,WAAO;AAAA,EACT;AACF;;;AD3DO,SAAS,iBAAiB,SAA4B;AAC3D,SAAO,eAAe,WAAW,SAAgC;AAC/D,UAAM,YAAY,QAAQ,QAAQ,IAAI,YAAY,KAAK;AACvD,UAAM,WAAW,QAAQ,QAAQ;AAEjC,QAAI,CAAC,MAAM,WAAW,QAAQ,SAAS,KAAK,cAAc,QAAQ,KAAK,WAAW,UAAU,QAAQ,YAAY,GAAG;AACjH;AAAA,IACF;AAEA,UAAM,OAAO,MAAM,iBAAiB,QAAQ,QAAQ,SAAS,GAAG,WAAW,QAAQ,SAAS,QAAQ,MAAM;AAE1G,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;AAAA,EACF;AACF;AAEO,IAAM,SAAS;AAAA,EACpB,SAAS,CAAC,mDAAmD;AAC/D;","names":[]}
package/dist/next.mjs CHANGED
@@ -3,17 +3,17 @@ import {
3
3
  isBot,
4
4
  isExcluded,
5
5
  isStaticAsset
6
- } from "./chunk-FPOJYG2E.mjs";
6
+ } from "./chunk-UQC64IMV.mjs";
7
7
 
8
8
  // src/next.ts
9
- function createMiddleware(options = {}) {
10
- return async function middleware2(request) {
9
+ function createMiddleware(options) {
10
+ return async function middleware(request) {
11
11
  const userAgent = request.headers.get("user-agent") || "";
12
12
  const pathname = request.nextUrl.pathname;
13
13
  if (!isBot(userAgent, options.extraBots) || isStaticAsset(pathname) || isExcluded(pathname, options.excludePaths)) {
14
14
  return;
15
15
  }
16
- const html = await fetchPrerendered(request.nextUrl.toString(), userAgent, options.apiUrl);
16
+ const html = await fetchPrerendered(request.nextUrl.toString(), userAgent, options.siteKey, options.apiUrl);
17
17
  if (html) {
18
18
  return new Response(html, {
19
19
  status: 200,
@@ -27,13 +27,11 @@ function createMiddleware(options = {}) {
27
27
  return;
28
28
  };
29
29
  }
30
- var middleware = createMiddleware();
31
30
  var config = {
32
31
  matcher: ["/((?!api|_next/static|_next/image|favicon.ico).*)"]
33
32
  };
34
33
  export {
35
34
  config,
36
- createMiddleware,
37
- middleware
35
+ createMiddleware
38
36
  };
39
37
  //# sourceMappingURL=next.mjs.map
package/dist/next.mjs.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/next.ts"],"sourcesContent":["/**\n * @rankdeploy/middleware/next — Next.js / Vercel middleware\n *\n * Usage in middleware.ts:\n * export { middleware, config } from '@rankdeploy/middleware/next'\n */\n\nimport { isBot, isStaticAsset, isExcluded, fetchPrerendered, type RankDeployOptions } from \"./index\";\n\ninterface NextMiddlewareRequest {\n headers: { get(name: string): string | null };\n nextUrl: { pathname: string; toString(): string };\n}\n\n/**\n * Create a Next.js middleware function with custom options.\n */\nexport function createMiddleware(options: RankDeployOptions = {}) {\n return async function middleware(request: NextMiddlewareRequest) {\n const userAgent = request.headers.get(\"user-agent\") || \"\";\n const pathname = request.nextUrl.pathname;\n\n // Skip non-bot, static assets, excluded paths\n if (!isBot(userAgent, options.extraBots) || isStaticAsset(pathname) || isExcluded(pathname, options.excludePaths)) {\n return; // undefined = next() in Next.js middleware\n }\n\n const html = await fetchPrerendered(request.nextUrl.toString(), userAgent, 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 // No pre-rendered version — let Next.js handle normally\n return;\n };\n}\n\n/**\n * Default middleware — ready to use.\n */\nexport const middleware = createMiddleware();\n\nexport const config = {\n matcher: [\"/((?!api|_next/static|_next/image|favicon.ico).*)\"],\n};\n"],"mappings":";;;;;;;;AAiBO,SAAS,iBAAiB,UAA6B,CAAC,GAAG;AAChE,SAAO,eAAeA,YAAW,SAAgC;AAC/D,UAAM,YAAY,QAAQ,QAAQ,IAAI,YAAY,KAAK;AACvD,UAAM,WAAW,QAAQ,QAAQ;AAGjC,QAAI,CAAC,MAAM,WAAW,QAAQ,SAAS,KAAK,cAAc,QAAQ,KAAK,WAAW,UAAU,QAAQ,YAAY,GAAG;AACjH;AAAA,IACF;AAEA,UAAM,OAAO,MAAM,iBAAiB,QAAQ,QAAQ,SAAS,GAAG,WAAW,QAAQ,MAAM;AAEzF,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;AAGA;AAAA,EACF;AACF;AAKO,IAAM,aAAa,iBAAiB;AAEpC,IAAM,SAAS;AAAA,EACpB,SAAS,CAAC,mDAAmD;AAC/D;","names":["middleware"]}
1
+ {"version":3,"sources":["../src/next.ts"],"sourcesContent":["/**\n * rankdeploy-middleware/next — Next.js / Vercel middleware\n *\n * Usage:\n * import { createMiddleware } from 'rankdeploy-middleware/next'\n * export const middleware = createMiddleware({ siteKey: 'your-site-key' })\n * export const config = { matcher: ['/((?!api|_next/static|_next/image|favicon.ico).*)'] }\n */\n\nimport { isBot, isStaticAsset, isExcluded, fetchPrerendered, 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 return async function middleware(request: NextMiddlewareRequest) {\n const userAgent = request.headers.get(\"user-agent\") || \"\";\n const pathname = request.nextUrl.pathname;\n\n if (!isBot(userAgent, options.extraBots) || isStaticAsset(pathname) || isExcluded(pathname, options.excludePaths)) {\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"],"mappings":";;;;;;;;AAgBO,SAAS,iBAAiB,SAA4B;AAC3D,SAAO,eAAe,WAAW,SAAgC;AAC/D,UAAM,YAAY,QAAQ,QAAQ,IAAI,YAAY,KAAK;AACvD,UAAM,WAAW,QAAQ,QAAQ;AAEjC,QAAI,CAAC,MAAM,WAAW,QAAQ,SAAS,KAAK,cAAc,QAAQ,KAAK,WAAW,UAAU,QAAQ,YAAY,GAAG;AACjH;AAAA,IACF;AAEA,UAAM,OAAO,MAAM,iBAAiB,QAAQ,QAAQ,SAAS,GAAG,WAAW,QAAQ,SAAS,QAAQ,MAAM;AAE1G,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;AAAA,EACF;AACF;AAEO,IAAM,SAAS;AAAA,EACpB,SAAS,CAAC,mDAAmD;AAC/D;","names":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rankdeploy-middleware",
3
- "version": "1.0.0",
3
+ "version": "1.1.0",
4
4
  "description": "SEO middleware for Rank Deploy — serves pre-rendered HTML to search engine bots",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",
@@ -27,12 +27,24 @@
27
27
  "types": "./dist/express.d.ts"
28
28
  }
29
29
  },
30
- "files": ["dist", "README.md"],
30
+ "files": [
31
+ "dist",
32
+ "README.md"
33
+ ],
31
34
  "scripts": {
32
35
  "build": "tsup",
33
36
  "prepublishOnly": "npm run build"
34
37
  },
35
- "keywords": ["seo", "prerender", "middleware", "nextjs", "netlify", "express", "rankdeploy", "googlebot"],
38
+ "keywords": [
39
+ "seo",
40
+ "prerender",
41
+ "middleware",
42
+ "nextjs",
43
+ "netlify",
44
+ "express",
45
+ "rankdeploy",
46
+ "googlebot"
47
+ ],
36
48
  "author": "Rank Deploy",
37
49
  "license": "MIT",
38
50
  "devDependencies": {
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/index.ts"],"sourcesContent":["/**\n * @rankdeploy/middleware — Core SEO middleware engine\n *\n * Detects search engine bots and serves pre-rendered HTML from Rank Deploy API.\n * Human visitors are not affected.\n *\n * Usage:\n * import { middleware } from '@rankdeploy/middleware/next' // Next.js\n * import { default } from '@rankdeploy/middleware/netlify' // Netlify\n * import { rankdeploy } from '@rankdeploy/middleware/express' // Express\n */\n\nexport const RANKDEPLOY_API = \"https://proxy.unikium.com\";\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];\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 /** Rank Deploy API URL. Default: https://proxy.unikium.com */\n apiUrl?: string;\n /** Additional bot user agents to detect */\n extraBots?: string[];\n /** Paths to exclude from pre-rendering */\n excludePaths?: string[];\n}\n\n/**\n * Check if a user agent string belongs to a bot.\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\n/**\n * Check if a path is a static asset.\n */\nexport function isStaticAsset(pathname: string): boolean {\n return STATIC_EXTENSIONS.test(pathname);\n}\n\n/**\n * Check if a path should be excluded.\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 * Returns the HTML string if available, null otherwise.\n */\nexport async function fetchPrerendered(\n url: string,\n userAgent: string,\n apiUrl = RANKDEPLOY_API,\n): Promise<string | null> {\n try {\n const res = await fetch(\n `${apiUrl}/render?url=${encodeURIComponent(url)}`,\n {\n headers: { \"User-Agent\": userAgent },\n signal: AbortSignal.timeout(10_000), // 10s timeout\n },\n );\n\n if (res.status === 200) {\n return res.text();\n }\n\n // 204 = passthrough (no cache), anything else = error\n return null;\n } catch {\n // Network error, timeout — fail silently\n return null;\n }\n}\n"],"mappings":";AAYO,IAAM,iBAAiB;AAEvB,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;AAClE;AAEO,IAAM,oBAAoB;AAc1B,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;AAKO,SAAS,cAAc,UAA2B;AACvD,SAAO,kBAAkB,KAAK,QAAQ;AACxC;AAKO,SAAS,WAAW,UAAkB,cAAkC;AAC7E,MAAI,CAAC,aAAc,QAAO;AAC1B,SAAO,aAAa,KAAK,CAAC,MAAM,SAAS,WAAW,CAAC,CAAC;AACxD;AAMA,eAAsB,iBACpB,KACA,WACA,SAAS,gBACe;AACxB,MAAI;AACF,UAAM,MAAM,MAAM;AAAA,MAChB,GAAG,MAAM,eAAe,mBAAmB,GAAG,CAAC;AAAA,MAC/C;AAAA,QACE,SAAS,EAAE,cAAc,UAAU;AAAA,QACnC,QAAQ,YAAY,QAAQ,GAAM;AAAA;AAAA,MACpC;AAAA,IACF;AAEA,QAAI,IAAI,WAAW,KAAK;AACtB,aAAO,IAAI,KAAK;AAAA,IAClB;AAGA,WAAO;AAAA,EACT,QAAQ;AAEN,WAAO;AAAA,EACT;AACF;","names":[]}
@@ -1,34 +0,0 @@
1
- import { RankDeployOptions } from './index.mjs';
2
-
3
- /**
4
- * @rankdeploy/middleware/express — Express.js middleware
5
- *
6
- * Usage:
7
- * import { rankdeploy } from '@rankdeploy/middleware/express'
8
- * app.use(rankdeploy())
9
- *
10
- * With options:
11
- * app.use(rankdeploy({ excludePaths: ['/api', '/admin'] }))
12
- */
13
-
14
- interface ExpressRequest {
15
- headers: Record<string, string | string[] | undefined>;
16
- url: string;
17
- protocol: string;
18
- get(name: string): string | undefined;
19
- }
20
- interface ExpressResponse {
21
- set(name: string, value: string): void;
22
- status(code: number): ExpressResponse;
23
- send(body: string): void;
24
- }
25
- type NextFunction = () => void;
26
- /**
27
- * Create Express middleware for Rank Deploy.
28
- *
29
- * Usage:
30
- * app.use(rankdeploy())
31
- */
32
- declare function rankdeploy(options?: RankDeployOptions): (req: ExpressRequest, res: ExpressResponse, next: NextFunction) => Promise<void>;
33
-
34
- export { rankdeploy as default, rankdeploy };
package/dist/express.d.ts DELETED
@@ -1,34 +0,0 @@
1
- import { RankDeployOptions } from './index.js';
2
-
3
- /**
4
- * @rankdeploy/middleware/express — Express.js middleware
5
- *
6
- * Usage:
7
- * import { rankdeploy } from '@rankdeploy/middleware/express'
8
- * app.use(rankdeploy())
9
- *
10
- * With options:
11
- * app.use(rankdeploy({ excludePaths: ['/api', '/admin'] }))
12
- */
13
-
14
- interface ExpressRequest {
15
- headers: Record<string, string | string[] | undefined>;
16
- url: string;
17
- protocol: string;
18
- get(name: string): string | undefined;
19
- }
20
- interface ExpressResponse {
21
- set(name: string, value: string): void;
22
- status(code: number): ExpressResponse;
23
- send(body: string): void;
24
- }
25
- type NextFunction = () => void;
26
- /**
27
- * Create Express middleware for Rank Deploy.
28
- *
29
- * Usage:
30
- * app.use(rankdeploy())
31
- */
32
- declare function rankdeploy(options?: RankDeployOptions): (req: ExpressRequest, res: ExpressResponse, next: NextFunction) => Promise<void>;
33
-
34
- export { rankdeploy as default, rankdeploy };
package/dist/index.d.mts DELETED
@@ -1,41 +0,0 @@
1
- /**
2
- * @rankdeploy/middleware — Core SEO middleware engine
3
- *
4
- * Detects search engine bots and serves pre-rendered HTML from Rank Deploy API.
5
- * Human visitors are not affected.
6
- *
7
- * Usage:
8
- * import { middleware } from '@rankdeploy/middleware/next' // Next.js
9
- * import { default } from '@rankdeploy/middleware/netlify' // Netlify
10
- * import { rankdeploy } from '@rankdeploy/middleware/express' // Express
11
- */
12
- declare const RANKDEPLOY_API = "https://proxy.unikium.com";
13
- declare const BOT_USER_AGENTS: string[];
14
- declare const STATIC_EXTENSIONS: RegExp;
15
- interface RankDeployOptions {
16
- /** Rank Deploy API URL. Default: https://proxy.unikium.com */
17
- apiUrl?: string;
18
- /** Additional bot user agents to detect */
19
- extraBots?: string[];
20
- /** Paths to exclude from pre-rendering */
21
- excludePaths?: string[];
22
- }
23
- /**
24
- * Check if a user agent string belongs to a bot.
25
- */
26
- declare function isBot(userAgent: string, extraBots?: string[]): boolean;
27
- /**
28
- * Check if a path is a static asset.
29
- */
30
- declare function isStaticAsset(pathname: string): boolean;
31
- /**
32
- * Check if a path should be excluded.
33
- */
34
- declare function isExcluded(pathname: string, excludePaths?: string[]): boolean;
35
- /**
36
- * Fetch pre-rendered HTML from Rank Deploy API.
37
- * Returns the HTML string if available, null otherwise.
38
- */
39
- declare function fetchPrerendered(url: string, userAgent: string, apiUrl?: string): Promise<string | null>;
40
-
41
- export { BOT_USER_AGENTS, RANKDEPLOY_API, type RankDeployOptions, STATIC_EXTENSIONS, fetchPrerendered, isBot, isExcluded, isStaticAsset };
package/dist/index.d.ts DELETED
@@ -1,41 +0,0 @@
1
- /**
2
- * @rankdeploy/middleware — Core SEO middleware engine
3
- *
4
- * Detects search engine bots and serves pre-rendered HTML from Rank Deploy API.
5
- * Human visitors are not affected.
6
- *
7
- * Usage:
8
- * import { middleware } from '@rankdeploy/middleware/next' // Next.js
9
- * import { default } from '@rankdeploy/middleware/netlify' // Netlify
10
- * import { rankdeploy } from '@rankdeploy/middleware/express' // Express
11
- */
12
- declare const RANKDEPLOY_API = "https://proxy.unikium.com";
13
- declare const BOT_USER_AGENTS: string[];
14
- declare const STATIC_EXTENSIONS: RegExp;
15
- interface RankDeployOptions {
16
- /** Rank Deploy API URL. Default: https://proxy.unikium.com */
17
- apiUrl?: string;
18
- /** Additional bot user agents to detect */
19
- extraBots?: string[];
20
- /** Paths to exclude from pre-rendering */
21
- excludePaths?: string[];
22
- }
23
- /**
24
- * Check if a user agent string belongs to a bot.
25
- */
26
- declare function isBot(userAgent: string, extraBots?: string[]): boolean;
27
- /**
28
- * Check if a path is a static asset.
29
- */
30
- declare function isStaticAsset(pathname: string): boolean;
31
- /**
32
- * Check if a path should be excluded.
33
- */
34
- declare function isExcluded(pathname: string, excludePaths?: string[]): boolean;
35
- /**
36
- * Fetch pre-rendered HTML from Rank Deploy API.
37
- * Returns the HTML string if available, null otherwise.
38
- */
39
- declare function fetchPrerendered(url: string, userAgent: string, apiUrl?: string): Promise<string | null>;
40
-
41
- export { BOT_USER_AGENTS, RANKDEPLOY_API, type RankDeployOptions, STATIC_EXTENSIONS, fetchPrerendered, isBot, isExcluded, isStaticAsset };
@@ -1,16 +0,0 @@
1
- import * as undici_types from 'undici-types';
2
- import { RankDeployOptions } from './index.mjs';
3
-
4
- interface NetlifyContext {
5
- next(): Promise<Response>;
6
- }
7
- /**
8
- * Create a Netlify Edge Function handler with custom options.
9
- */
10
- declare function createHandler(options?: RankDeployOptions): (request: Request, context: NetlifyContext) => Promise<undici_types.Response>;
11
- /**
12
- * Default handler — ready to use as-is.
13
- */
14
- declare const _default: (request: Request, context: NetlifyContext) => Promise<undici_types.Response>;
15
-
16
- export { createHandler, _default as default };
package/dist/netlify.d.ts DELETED
@@ -1,16 +0,0 @@
1
- import * as undici_types from 'undici-types';
2
- import { RankDeployOptions } from './index.js';
3
-
4
- interface NetlifyContext {
5
- next(): Promise<Response>;
6
- }
7
- /**
8
- * Create a Netlify Edge Function handler with custom options.
9
- */
10
- declare function createHandler(options?: RankDeployOptions): (request: Request, context: NetlifyContext) => Promise<undici_types.Response>;
11
- /**
12
- * Default handler — ready to use as-is.
13
- */
14
- declare const _default: (request: Request, context: NetlifyContext) => Promise<undici_types.Response>;
15
-
16
- export { createHandler, _default as default };
package/dist/next.d.mts DELETED
@@ -1,25 +0,0 @@
1
- import * as undici_types from 'undici-types';
2
- import { RankDeployOptions } from './index.mjs';
3
-
4
- interface NextMiddlewareRequest {
5
- headers: {
6
- get(name: string): string | null;
7
- };
8
- nextUrl: {
9
- pathname: string;
10
- toString(): string;
11
- };
12
- }
13
- /**
14
- * Create a Next.js middleware function with custom options.
15
- */
16
- declare function createMiddleware(options?: RankDeployOptions): (request: NextMiddlewareRequest) => Promise<undici_types.Response | undefined>;
17
- /**
18
- * Default middleware — ready to use.
19
- */
20
- declare const middleware: (request: NextMiddlewareRequest) => Promise<undici_types.Response | undefined>;
21
- declare const config: {
22
- matcher: string[];
23
- };
24
-
25
- export { config, createMiddleware, middleware };
package/dist/next.d.ts DELETED
@@ -1,25 +0,0 @@
1
- import * as undici_types from 'undici-types';
2
- import { RankDeployOptions } from './index.js';
3
-
4
- interface NextMiddlewareRequest {
5
- headers: {
6
- get(name: string): string | null;
7
- };
8
- nextUrl: {
9
- pathname: string;
10
- toString(): string;
11
- };
12
- }
13
- /**
14
- * Create a Next.js middleware function with custom options.
15
- */
16
- declare function createMiddleware(options?: RankDeployOptions): (request: NextMiddlewareRequest) => Promise<undici_types.Response | undefined>;
17
- /**
18
- * Default middleware — ready to use.
19
- */
20
- declare const middleware: (request: NextMiddlewareRequest) => Promise<undici_types.Response | undefined>;
21
- declare const config: {
22
- matcher: string[];
23
- };
24
-
25
- export { config, createMiddleware, middleware };