@searchos/bot-proxy 1.0.2 → 1.0.4
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-3GWBNF6R.js +1 -0
- package/dist/chunk-62QI7OUQ.js +1 -0
- package/dist/chunk-HLBLRAGQ.js +1 -0
- package/dist/cloudflare.cjs +1 -0
- package/dist/cloudflare.d.cts +26 -0
- package/dist/cloudflare.d.ts +26 -0
- package/dist/cloudflare.js +1 -0
- package/dist/index.cjs +1 -1
- package/dist/index.d.cts +2 -48
- package/dist/index.d.ts +2 -48
- package/dist/index.js +1 -1
- package/dist/nextjs.cjs +1 -0
- package/dist/nextjs.d.cts +23 -0
- package/dist/nextjs.d.ts +23 -0
- package/dist/nextjs.js +1 -0
- package/package.json +12 -2
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{b as O,c as f}from"./chunk-62QI7OUQ.js";var P=/^\/(?:robots\.txt|llms\.txt|sitemap[^\/]*\.(?:xml|xsl))$/i,S=/mobile|android|iphone|phone|tablet|webos|ipad/i;async function E(s,r){let{projectId:t,cloudfrontDomain:p,prerenderDomain:n,botLogEndpoint:a,aiRender:x=!0,ocr:y=!0,aiPathPrefixes:$=[]}=r,o=r.siteDomain.replace(/^https?:\/\//,"").replace(/\/+$/,""),b=p.replace(/\/$/,""),l=new URL(s.url),e=l.pathname;if(s.headers.get("x-prerender-host")){if(P.test(e)||e===`/${t}.txt`){let{NextResponse:i}=await import("next/server");return i.next()}return null}if(e===`/${t}.txt`)try{let i=await fetch(`${n}${e}`,{redirect:"manual"});return new Response(i.body,{status:i.status,headers:{"Content-Type":"text/plain","Cache-Control":"public, max-age=3600"}})}catch{return null}if(P.test(e))try{let i=await fetch(`${n}/static${e}`,{headers:{"X-Signature":t,"X-Original-Host":o}});return new Response(i.body,{status:i.status,headers:{"Content-Type":i.headers.get("Content-Type")||"text/plain","Cache-Control":"public, max-age=3600"}})}catch{return null}let c=s.headers.get("user-agent")||"",u=O(c);if(!u)return null;let k=S.test(c)?"mobile":"desktop",d=`https://${o}${e}`;try{if(u.isAi&&x){let m=await f(e,"ai"),_=await fetch(`${b}/v2/${o}/${m}.html`,{headers:{Accept:"text/html"}});if(_.ok){let h=await _.text();if(h&&h.length>100)return g(a,t,o,e,l.search,c,"hit_ai"),R(n,t,d,y,$),w(h,"HIT-AI",u.name)}let I=await f(e,"desktop"),j=await fetch(`${b}/v2/${o}/${I}.html`,{headers:{Accept:"text/html"}});if(j.ok){let h=await j.text();if(h&&h.length>100)return g(a,t,o,e,l.search,c,"hit_desktop_fallback"),R(n,t,d,y,$),w(h,"HIT-DESKTOP",u.name)}return g(a,t,o,e,l.search,c,"miss_ai"),R(n,t,d,y,$),T(n,t,d),null}let i=await f(e,k),C=await fetch(`${b}/v2/${o}/${i}.html`,{headers:{Accept:"text/html"}});if(C.ok){let m=await C.text();if(m&&m.length>100)return g(a,t,o,e,l.search,c,"hit"),T(n,t,d),w(m,"HIT",u.name)}}catch{}return g(a,t,o,e,l.search,c,"miss"),T(n,t,d),null}function w(s,r,t){return new Response(s,{headers:{"Content-Type":"text/html; charset=utf-8","X-Cache":r,"X-Bot":t}})}function g(s,r,t,p,n,a,x){fetch(s,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({project_id:r,url:`https://${t}${p}${n}`,domain:t,path:p,user_agent:a,phase:x})}).catch(()=>{})}function T(s,r,t){fetch(`${s}/v2/cache`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({items:[{url:t,project_id:r}]})}).catch(()=>{})}function R(s,r,t,p,n){let a={items:[{url:t,project_id:r}],ocr:p};n.length>0&&(a.path_prefixes=n),fetch(`${s}/v2/cache/ai`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(a)}).catch(()=>{})}export{E as a};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
var d=(e=>typeof require<"u"?require:typeof Proxy<"u"?new Proxy(e,{get:(r,t)=>(typeof require<"u"?require:r)[t]}):e)(function(e){if(typeof require<"u")return require.apply(this,arguments);throw Error('Dynamic require of "'+e+'" is not supported')});var n=["chatgpt-user","claude-user","perplexity-user","gemini-user","gemini-deep-research","mistralai-user","grok-user"],i=["gptbot","oai-searchbot","claudebot","claude-searchbot","google-extended","google-cloudvertexbot","perplexitybot","meta-externalagent","applebot-extended","amazonbot","cohere-ai","bytespider","deepseekbot","grokbot","ccbot","diffbot","ai2bot","petalbot"],a=["googlebot","googlebot-image","googlebot-video","googlebot-news","googleother","mediapartners-google","adsbot-google","google-inspectiontool","bingbot","bingpreview","naverbot","yeti","daumoa","baiduspider","yandexbot","duckduckbot","applebot"],c=["facebookexternalhit","linkedinbot","twitterbot","slackbot","discordbot","telegrambot","whatsapp","pinterestbot","redditbot"],g=["ahrefsbot","semrushbot","mj12bot","dotbot","dataforseobot"],l=["uptimerobot","lighthouse","chrome-lighthouse"],s=new Set([...n,...i]),u=new Set(n),b=[...n,...i,...a,...c,...g,...l];function m(e){let r=e.toLowerCase();for(let t of b)if(r.includes(t)){let o;return u.has(t)?o="ai-user":s.has(t)?o="ai-crawl":a.includes(t)?o="search":c.includes(t)?o="sns":g.includes(t)?o="seo":o="monitoring",{name:t,isAi:s.has(t),category:o}}return null}async function p(e){if(typeof process<"u"&&process.versions?.node){let{createHash:o}=d("crypto");return o("md5").update(e,"utf8").digest("hex")}let r=new TextEncoder().encode(e),t=await crypto.subtle.digest("MD5",r);return Array.from(new Uint8Array(t),o=>o.toString(16).padStart(2,"0")).join("")}function f(e){if(!e)return"/";if(e.startsWith("http://")||e.startsWith("https://"))try{e=new URL(e).pathname}catch{}let r=e.indexOf("?");return r!==-1&&(e=e.substring(0,r)),e?e.split("/").map(t=>{if(!t)return t;try{return encodeURIComponent(decodeURIComponent(t))}catch{return encodeURIComponent(t)}}).join("/"):"/"}async function y(e,r){let t=f(e);return`${await p(t)}_${r}`}export{u as a,m as b,y as c};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{a as E,b as R,c as w}from"./chunk-62QI7OUQ.js";var S=/^\/(?:robots\.txt|llms\.txt|sitemap[^\/]*\.(?:xml|xsl))$/i,I=/mobile|android|iphone|phone|tablet|webos|ipad/i;async function V(s,n,r,p){let{projectId:t,siteDomain:u,prerenderDomain:i,botLogEndpoint:h,aiRender:k=!0,ocr:$=!0,aiPathPrefixes:C=[]}=p,e=new URL(s.url).pathname,c=u.replace(/^https?:\/\//,"").replace(/\/+$/,"");if(s.headers.get("x-prerender-host"))return null;if(e===`/${t}.txt`)try{let o=await fetch(`${i}${e}`,{redirect:"manual"});return new Response(o.body,{status:o.status,headers:{"Content-Type":"text/plain","Cache-Control":"public, max-age=3600"}})}catch{return new Response("",{status:404})}if(S.test(e))try{let o=await fetch(`${i}/static${e}`,{redirect:"manual",headers:{"X-Signature":t,"X-Original-Host":c}});return new Response(o.body,{status:o.status,headers:{"Content-Type":o.headers.get("Content-Type")||"text/plain","Cache-Control":"public, max-age=3600"}})}catch{return null}let l=s.headers.get("user-agent")||"",a=R(l);if(!a||!n.V2_CACHE)return null;let P=I.test(l)?"mobile":"desktop",d=`https://${c}${e}`,g=E.has(a.name)?"ai-user":a.isAi?"ai-crawl":"standard",m=o=>r.waitUntil(o().catch(f=>console.error("[bot-proxy]",f)));try{if(a.isAi&&k){let A=await w(e,"ai"),x=await n.V2_CACHE.get(A);if(x)return m(async()=>{console.log(`[BOT] ${a.name} | ${g} | hit_ai | ${e}`),await y(h,t,c,e,l,"hit_ai"),await _(i,t,d,$,C)}),b(x,"HIT-AI",a.name);let H=await w(e,"desktop"),O=await n.V2_CACHE.get(H);return O?(m(async()=>{console.log(`[BOT] ${a.name} | ${g} | hit_desktop_fallback | ${e}`),await y(h,t,c,e,l,"hit_desktop_fallback"),await _(i,t,d,$,C)}),b(O,"HIT-DESKTOP",a.name)):(m(async()=>{console.log(`[BOT] ${a.name} | ${g} | miss_ai | ${e}`),await y(h,t,c,e,l,"miss_ai"),await Promise.all([_(i,t,d,$,C),T(i,t,d)])}),null)}let o=await w(e,P),f=await n.V2_CACHE.get(o);return f?(m(async()=>{console.log(`[BOT] ${a.name} | ${g} | hit | ${e}`),await y(h,t,c,e,l,"hit"),await T(i,t,d)}),b(f,"HIT",a.name)):(m(async()=>{console.log(`[BOT] ${a.name} | ${g} | miss | ${e}`),await y(h,t,c,e,l,"miss"),await T(i,t,d)}),null)}catch(o){return console.error("[bot-proxy]",o),null}}function b(s,n,r){return new Response(s,{headers:{"Content-Type":"text/html; charset=utf-8","X-Cache":n,"X-Bot":r}})}async function y(s,n,r,p,t,u){await fetch(s,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({project_id:n,url:`https://${r}${p}`,domain:r,path:p,user_agent:t,phase:u})})}async function T(s,n,r){await fetch(`${s}/v2/cache/kv`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({items:[{url:r,project_id:n}]})})}async function _(s,n,r,p,t){let u={items:[{url:r,project_id:n}],ocr:p};t.length>0&&(u.path_prefixes=t),await fetch(`${s}/v2/cache/kv/ai`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(u)})}export{V as a};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";var _=Object.defineProperty;var v=Object.getOwnPropertyDescriptor;var V=Object.getOwnPropertyNames;var D=Object.prototype.hasOwnProperty;var M=(t,o)=>{for(var e in o)_(t,e,{get:o[e],enumerable:!0})},X=(t,o,e,r)=>{if(o&&typeof o=="object"||typeof o=="function")for(let n of V(o))!D.call(t,n)&&n!==e&&_(t,n,{get:()=>o[n],enumerable:!(r=v(o,n))||r.enumerable});return t};var z=t=>X(_({},"__esModule",{value:!0}),t);var Y={};M(Y,{cloudflareProxy:()=>H});module.exports=z(Y);var T=["chatgpt-user","claude-user","perplexity-user","gemini-user","gemini-deep-research","mistralai-user","grok-user"],k=["gptbot","oai-searchbot","claudebot","claude-searchbot","google-extended","google-cloudvertexbot","perplexitybot","meta-externalagent","applebot-extended","amazonbot","cohere-ai","bytespider","deepseekbot","grokbot","ccbot","diffbot","ai2bot","petalbot"],A=["googlebot","googlebot-image","googlebot-video","googlebot-news","googleother","mediapartners-google","adsbot-google","google-inspectiontool","bingbot","bingpreview","naverbot","yeti","daumoa","baiduspider","yandexbot","duckduckbot","applebot"],B=["facebookexternalhit","linkedinbot","twitterbot","slackbot","discordbot","telegrambot","whatsapp","pinterestbot","redditbot"],P=["ahrefsbot","semrushbot","mj12bot","dotbot","dataforseobot"],J=["uptimerobot","lighthouse","chrome-lighthouse"],R=new Set([...T,...k]),C=new Set(T),W=[...T,...k,...A,...B,...P,...J];function N(t){let o=t.toLowerCase();for(let e of W)if(o.includes(e)){let r;return C.has(e)?r="ai-user":R.has(e)?r="ai-crawl":A.includes(e)?r="search":B.includes(e)?r="sns":P.includes(e)?r="seo":r="monitoring",{name:e,isAi:R.has(e),category:r}}return null}async function G(t){if(typeof process<"u"&&process.versions?.node){let{createHash:r}=require("crypto");return r("md5").update(t,"utf8").digest("hex")}let o=new TextEncoder().encode(t),e=await crypto.subtle.digest("MD5",o);return Array.from(new Uint8Array(e),r=>r.toString(16).padStart(2,"0")).join("")}function q(t){if(!t)return"/";if(t.startsWith("http://")||t.startsWith("https://"))try{t=new URL(t).pathname}catch{}let o=t.indexOf("?");return o!==-1&&(t=t.substring(0,o)),t?t.split("/").map(e=>{if(!e)return e;try{return encodeURIComponent(decodeURIComponent(e))}catch{return encodeURIComponent(e)}}).join("/"):"/"}async function y(t,o){let e=q(t);return`${await G(e)}_${o}`}var F=/^\/(?:robots\.txt|llms\.txt|sitemap[^\/]*\.(?:xml|xsl))$/i,Q=/mobile|android|iphone|phone|tablet|webos|ipad/i;async function H(t,o,e,r){let{projectId:n,siteDomain:d,prerenderDomain:c,botLogEndpoint:g,aiRender:K=!0,ocr:x=!0,aiPathPrefixes:w=[]}=r,s=new URL(t.url).pathname,l=d.replace(/^https?:\/\//,"").replace(/\/+$/,"");if(t.headers.get("x-prerender-host"))return null;if(s===`/${n}.txt`)try{let i=await fetch(`${c}${s}`,{redirect:"manual"});return new Response(i.body,{status:i.status,headers:{"Content-Type":"text/plain","Cache-Control":"public, max-age=3600"}})}catch{return new Response("",{status:404})}if(F.test(s))try{let i=await fetch(`${c}/static${s}`,{redirect:"manual",headers:{"X-Signature":n,"X-Original-Host":l}});return new Response(i.body,{status:i.status,headers:{"Content-Type":i.headers.get("Content-Type")||"text/plain","Cache-Control":"public, max-age=3600"}})}catch{return null}let p=t.headers.get("user-agent")||"",a=N(p);if(!a||!o.V2_CACHE)return null;let j=Q.test(p)?"mobile":"desktop",u=`https://${l}${s}`,h=C.has(a.name)?"ai-user":a.isAi?"ai-crawl":"standard",m=i=>e.waitUntil(i().catch(b=>console.error("[bot-proxy]",b)));try{if(a.isAi&&K){let L=await y(s,"ai"),$=await o.V2_CACHE.get(L);if($)return m(async()=>{console.log(`[BOT] ${a.name} | ${h} | hit_ai | ${s}`),await f(g,n,l,s,p,"hit_ai"),await S(c,n,u,x,w)}),O($,"HIT-AI",a.name);let U=await y(s,"desktop"),I=await o.V2_CACHE.get(U);return I?(m(async()=>{console.log(`[BOT] ${a.name} | ${h} | hit_desktop_fallback | ${s}`),await f(g,n,l,s,p,"hit_desktop_fallback"),await S(c,n,u,x,w)}),O(I,"HIT-DESKTOP",a.name)):(m(async()=>{console.log(`[BOT] ${a.name} | ${h} | miss_ai | ${s}`),await f(g,n,l,s,p,"miss_ai"),await Promise.all([S(c,n,u,x,w),E(c,n,u)])}),null)}let i=await y(s,j),b=await o.V2_CACHE.get(i);return b?(m(async()=>{console.log(`[BOT] ${a.name} | ${h} | hit | ${s}`),await f(g,n,l,s,p,"hit"),await E(c,n,u)}),O(b,"HIT",a.name)):(m(async()=>{console.log(`[BOT] ${a.name} | ${h} | miss | ${s}`),await f(g,n,l,s,p,"miss"),await E(c,n,u)}),null)}catch(i){return console.error("[bot-proxy]",i),null}}function O(t,o,e){return new Response(t,{headers:{"Content-Type":"text/html; charset=utf-8","X-Cache":o,"X-Bot":e}})}async function f(t,o,e,r,n,d){await fetch(t,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({project_id:o,url:`https://${e}${r}`,domain:e,path:r,user_agent:n,phase:d})})}async function E(t,o,e){await fetch(`${t}/v2/cache/kv`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({items:[{url:e,project_id:o}]})})}async function S(t,o,e,r,n){let d={items:[{url:e,project_id:o}],ocr:r};n.length>0&&(d.path_prefixes=n),await fetch(`${t}/v2/cache/kv/ai`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(d)})}0&&(module.exports={cloudflareProxy});
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
interface CloudflareProxyOptions {
|
|
2
|
+
projectId: string;
|
|
3
|
+
/** 사이트 도메인 (예: "example.com") */
|
|
4
|
+
siteDomain: string;
|
|
5
|
+
prerenderDomain: string;
|
|
6
|
+
botLogEndpoint: string;
|
|
7
|
+
/** AI 렌더 활성화 (기본: true). true면 AI 봇에게 ai 캐시를 우선 서빙 */
|
|
8
|
+
aiRender?: boolean;
|
|
9
|
+
/** OCR 활성화 (기본: true). AI 워밍 요청 시 OCR 포함 여부 */
|
|
10
|
+
ocr?: boolean;
|
|
11
|
+
/** AI 렌더 경로 prefix (빈 배열 = 전체 경로) */
|
|
12
|
+
aiPathPrefixes?: string[];
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Cloudflare Worker에서 봇 요청을 KV 캐시로 프록시.
|
|
16
|
+
* 봇이 아니거나 캐시 미스면 null 반환.
|
|
17
|
+
*
|
|
18
|
+
* AI 봇: ai 캐시 → desktop 폴백 → null (origin)
|
|
19
|
+
* 일반 봇: desktop/mobile 캐시 → null (origin)
|
|
20
|
+
*/
|
|
21
|
+
declare function cloudflareProxy(request: Request, env: {
|
|
22
|
+
V2_CACHE?: KVNamespace;
|
|
23
|
+
[key: string]: unknown;
|
|
24
|
+
}, ctx: ExecutionContext, options: CloudflareProxyOptions): Promise<Response | null>;
|
|
25
|
+
|
|
26
|
+
export { type CloudflareProxyOptions, cloudflareProxy };
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
interface CloudflareProxyOptions {
|
|
2
|
+
projectId: string;
|
|
3
|
+
/** 사이트 도메인 (예: "example.com") */
|
|
4
|
+
siteDomain: string;
|
|
5
|
+
prerenderDomain: string;
|
|
6
|
+
botLogEndpoint: string;
|
|
7
|
+
/** AI 렌더 활성화 (기본: true). true면 AI 봇에게 ai 캐시를 우선 서빙 */
|
|
8
|
+
aiRender?: boolean;
|
|
9
|
+
/** OCR 활성화 (기본: true). AI 워밍 요청 시 OCR 포함 여부 */
|
|
10
|
+
ocr?: boolean;
|
|
11
|
+
/** AI 렌더 경로 prefix (빈 배열 = 전체 경로) */
|
|
12
|
+
aiPathPrefixes?: string[];
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Cloudflare Worker에서 봇 요청을 KV 캐시로 프록시.
|
|
16
|
+
* 봇이 아니거나 캐시 미스면 null 반환.
|
|
17
|
+
*
|
|
18
|
+
* AI 봇: ai 캐시 → desktop 폴백 → null (origin)
|
|
19
|
+
* 일반 봇: desktop/mobile 캐시 → null (origin)
|
|
20
|
+
*/
|
|
21
|
+
declare function cloudflareProxy(request: Request, env: {
|
|
22
|
+
V2_CACHE?: KVNamespace;
|
|
23
|
+
[key: string]: unknown;
|
|
24
|
+
}, ctx: ExecutionContext, options: CloudflareProxyOptions): Promise<Response | null>;
|
|
25
|
+
|
|
26
|
+
export { type CloudflareProxyOptions, cloudflareProxy };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{a as o}from"./chunk-HLBLRAGQ.js";import"./chunk-62QI7OUQ.js";export{o as cloudflareProxy};
|
package/dist/index.cjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";var
|
|
1
|
+
"use strict";var F=Object.create;var E=Object.defineProperty;var G=Object.getOwnPropertyDescriptor;var q=Object.getOwnPropertyNames;var Q=Object.getPrototypeOf,Y=Object.prototype.hasOwnProperty;var Z=(e,o)=>{for(var t in o)E(e,t,{get:o[t],enumerable:!0})},H=(e,o,t,s)=>{if(o&&typeof o=="object"||typeof o=="function")for(let n of q(o))!Y.call(e,n)&&n!==t&&E(e,n,{get:()=>o[n],enumerable:!(s=G(o,n))||s.enumerable});return e};var tt=(e,o,t)=>(t=e!=null?F(Q(e)):{},H(o||!e||!e.__esModule?E(t,"default",{value:e,enumerable:!0}):t,e)),et=e=>H(E({},"__esModule",{value:!0}),e);var lt={};Z(lt,{cloudflareProxy:()=>z,nextjsProxy:()=>M});module.exports=et(lt);var I=["chatgpt-user","claude-user","perplexity-user","gemini-user","gemini-deep-research","mistralai-user","grok-user"],D=["gptbot","oai-searchbot","claudebot","claude-searchbot","google-extended","google-cloudvertexbot","perplexitybot","meta-externalagent","applebot-extended","amazonbot","cohere-ai","bytespider","deepseekbot","grokbot","ccbot","diffbot","ai2bot","petalbot"],U=["googlebot","googlebot-image","googlebot-video","googlebot-news","googleother","mediapartners-google","adsbot-google","google-inspectiontool","bingbot","bingpreview","naverbot","yeti","daumoa","baiduspider","yandexbot","duckduckbot","applebot"],X=["facebookexternalhit","linkedinbot","twitterbot","slackbot","discordbot","telegrambot","whatsapp","pinterestbot","redditbot"],V=["ahrefsbot","semrushbot","mj12bot","dotbot","dataforseobot"],ot=["uptimerobot","lighthouse","chrome-lighthouse"],v=new Set([...I,...D]),k=new Set(I),nt=[...I,...D,...U,...X,...V,...ot];function R(e){let o=e.toLowerCase();for(let t of nt)if(o.includes(t)){let s;return k.has(t)?s="ai-user":v.has(t)?s="ai-crawl":U.includes(t)?s="search":X.includes(t)?s="sns":V.includes(t)?s="seo":s="monitoring",{name:t,isAi:v.has(t),category:s}}return null}async function rt(e){if(typeof process<"u"&&process.versions?.node){let{createHash:s}=require("crypto");return s("md5").update(e,"utf8").digest("hex")}let o=new TextEncoder().encode(e),t=await crypto.subtle.digest("MD5",o);return Array.from(new Uint8Array(t),s=>s.toString(16).padStart(2,"0")).join("")}function st(e){if(!e)return"/";if(e.startsWith("http://")||e.startsWith("https://"))try{e=new URL(e).pathname}catch{}let o=e.indexOf("?");return o!==-1&&(e=e.substring(0,o)),e?e.split("/").map(t=>{if(!t)return t;try{return encodeURIComponent(decodeURIComponent(t))}catch{return encodeURIComponent(t)}}).join("/"):"/"}async function b(e,o){let t=st(e);return`${await rt(t)}_${o}`}var J=/^\/(?:robots\.txt|llms\.txt|sitemap[^\/]*\.(?:xml|xsl))$/i,at=/mobile|android|iphone|phone|tablet|webos|ipad/i;async function M(e,o){let{projectId:t,cloudfrontDomain:s,prerenderDomain:n,botLogEndpoint:a,aiRender:h=!0,ocr:f=!0,aiPathPrefixes:$=[]}=o,p=o.siteDomain.replace(/^https?:\/\//,"").replace(/\/+$/,""),w=s.replace(/\/$/,""),T=new URL(e.url),r=T.pathname;if(e.headers.get("x-prerender-host")){if(J.test(r)||r===`/${t}.txt`){let{NextResponse:i}=await import("next/server");return i.next()}return null}if(r===`/${t}.txt`)try{let i=await fetch(`${n}${r}`,{redirect:"manual"});return new Response(i.body,{status:i.status,headers:{"Content-Type":"text/plain","Cache-Control":"public, max-age=3600"}})}catch{return null}if(J.test(r))try{let i=await fetch(`${n}/static${r}`,{headers:{"X-Signature":t,"X-Original-Host":p}});return new Response(i.body,{status:i.status,headers:{"Content-Type":i.headers.get("Content-Type")||"text/plain","Cache-Control":"public, max-age=3600"}})}catch{return null}let c=e.headers.get("user-agent")||"",u=R(c);if(!u)return null;let d=at.test(c)?"mobile":"desktop",y=`https://${p}${r}`;try{if(u.isAi&&h){let g=await b(r,"ai"),l=await fetch(`${w}/v2/${p}/${g}.html`,{headers:{Accept:"text/html"}});if(l.ok){let m=await l.text();if(m&&m.length>100)return C(a,t,p,r,T.search,c,"hit_ai"),j(n,t,y,f,$),A(m,"HIT-AI",u.name)}let _=await b(r,"desktop"),S=await fetch(`${w}/v2/${p}/${_}.html`,{headers:{Accept:"text/html"}});if(S.ok){let m=await S.text();if(m&&m.length>100)return C(a,t,p,r,T.search,c,"hit_desktop_fallback"),j(n,t,y,f,$),A(m,"HIT-DESKTOP",u.name)}return C(a,t,p,r,T.search,c,"miss_ai"),j(n,t,y,f,$),P(n,t,y),null}let i=await b(r,d),x=await fetch(`${w}/v2/${p}/${i}.html`,{headers:{Accept:"text/html"}});if(x.ok){let g=await x.text();if(g&&g.length>100)return C(a,t,p,r,T.search,c,"hit"),P(n,t,y),A(g,"HIT",u.name)}}catch{}return C(a,t,p,r,T.search,c,"miss"),P(n,t,y),null}function A(e,o,t){return new Response(e,{headers:{"Content-Type":"text/html; charset=utf-8","X-Cache":o,"X-Bot":t}})}function C(e,o,t,s,n,a,h){fetch(e,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({project_id:o,url:`https://${t}${s}${n}`,domain:t,path:s,user_agent:a,phase:h})}).catch(()=>{})}function P(e,o,t){fetch(`${e}/v2/cache`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({items:[{url:t,project_id:o}]})}).catch(()=>{})}function j(e,o,t,s,n){let a={items:[{url:t,project_id:o}],ocr:s};n.length>0&&(a.path_prefixes=n),fetch(`${e}/v2/cache/ai`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(a)}).catch(()=>{})}var it=/^\/(?:robots\.txt|llms\.txt|sitemap[^\/]*\.(?:xml|xsl))$/i,ct=/mobile|android|iphone|phone|tablet|webos|ipad/i;async function z(e,o,t,s){let{projectId:n,siteDomain:a,prerenderDomain:h,botLogEndpoint:f,aiRender:$=!0,ocr:p=!0,aiPathPrefixes:w=[]}=s,r=new URL(e.url).pathname,c=a.replace(/^https?:\/\//,"").replace(/\/+$/,"");if(e.headers.get("x-prerender-host"))return null;if(r===`/${n}.txt`)try{let l=await fetch(`${h}${r}`,{redirect:"manual"});return new Response(l.body,{status:l.status,headers:{"Content-Type":"text/plain","Cache-Control":"public, max-age=3600"}})}catch{return new Response("",{status:404})}if(it.test(r))try{let l=await fetch(`${h}/static${r}`,{redirect:"manual",headers:{"X-Signature":n,"X-Original-Host":c}});return new Response(l.body,{status:l.status,headers:{"Content-Type":l.headers.get("Content-Type")||"text/plain","Cache-Control":"public, max-age=3600"}})}catch{return null}let u=e.headers.get("user-agent")||"",d=R(u);if(!d||!o.V2_CACHE)return null;let y=ct.test(u)?"mobile":"desktop",i=`https://${c}${r}`,x=k.has(d.name)?"ai-user":d.isAi?"ai-crawl":"standard",g=l=>t.waitUntil(l().catch(_=>console.error("[bot-proxy]",_)));try{if(d.isAi&&$){let S=await b(r,"ai"),m=await o.V2_CACHE.get(S);if(m)return g(async()=>{console.log(`[BOT] ${d.name} | ${x} | hit_ai | ${r}`),await O(f,n,c,r,u,"hit_ai"),await L(h,n,i,p,w)}),B(m,"HIT-AI",d.name);let W=await b(r,"desktop"),K=await o.V2_CACHE.get(W);return K?(g(async()=>{console.log(`[BOT] ${d.name} | ${x} | hit_desktop_fallback | ${r}`),await O(f,n,c,r,u,"hit_desktop_fallback"),await L(h,n,i,p,w)}),B(K,"HIT-DESKTOP",d.name)):(g(async()=>{console.log(`[BOT] ${d.name} | ${x} | miss_ai | ${r}`),await O(f,n,c,r,u,"miss_ai"),await Promise.all([L(h,n,i,p,w),N(h,n,i)])}),null)}let l=await b(r,y),_=await o.V2_CACHE.get(l);return _?(g(async()=>{console.log(`[BOT] ${d.name} | ${x} | hit | ${r}`),await O(f,n,c,r,u,"hit"),await N(h,n,i)}),B(_,"HIT",d.name)):(g(async()=>{console.log(`[BOT] ${d.name} | ${x} | miss | ${r}`),await O(f,n,c,r,u,"miss"),await N(h,n,i)}),null)}catch(l){return console.error("[bot-proxy]",l),null}}function B(e,o,t){return new Response(e,{headers:{"Content-Type":"text/html; charset=utf-8","X-Cache":o,"X-Bot":t}})}async function O(e,o,t,s,n,a){await fetch(e,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({project_id:o,url:`https://${t}${s}`,domain:t,path:s,user_agent:n,phase:a})})}async function N(e,o,t){await fetch(`${e}/v2/cache/kv`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({items:[{url:t,project_id:o}]})})}async function L(e,o,t,s,n){let a={items:[{url:t,project_id:o}],ocr:s};n.length>0&&(a.path_prefixes=n),await fetch(`${e}/v2/cache/kv/ai`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(a)})}0&&(module.exports={cloudflareProxy,nextjsProxy});
|
package/dist/index.d.cts
CHANGED
|
@@ -1,48 +1,2 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
siteDomain: string;
|
|
4
|
-
cloudfrontDomain: string;
|
|
5
|
-
prerenderDomain: string;
|
|
6
|
-
botLogEndpoint: string;
|
|
7
|
-
/** AI 렌더 활성화 (기본: true). true면 AI 봇에게 ai 캐시를 우선 서빙 */
|
|
8
|
-
aiRender?: boolean;
|
|
9
|
-
/** OCR 활성화 (기본: true). AI 워밍 요청 시 OCR 포함 여부 */
|
|
10
|
-
ocr?: boolean;
|
|
11
|
-
/** AI 렌더 경로 prefix (빈 배열 = 전체 경로) */
|
|
12
|
-
aiPathPrefixes?: string[];
|
|
13
|
-
}
|
|
14
|
-
/**
|
|
15
|
-
* Next.js middleware에서 봇 요청을 CloudFront 캐시로 프록시.
|
|
16
|
-
* 봇이 아니거나 캐시 미스면 null 반환.
|
|
17
|
-
*
|
|
18
|
-
* AI 봇: ai 캐시 → desktop 폴백 → null (origin)
|
|
19
|
-
* 일반 봇: desktop/mobile 캐시 → null (origin)
|
|
20
|
-
*/
|
|
21
|
-
declare function nextjsProxy(request: Request, options: NextjsProxyOptions): Promise<Response | null>;
|
|
22
|
-
|
|
23
|
-
interface CloudflareProxyOptions {
|
|
24
|
-
projectId: string;
|
|
25
|
-
/** 사이트 도메인 (예: "example.com") */
|
|
26
|
-
siteDomain: string;
|
|
27
|
-
prerenderDomain: string;
|
|
28
|
-
botLogEndpoint: string;
|
|
29
|
-
/** AI 렌더 활성화 (기본: true). true면 AI 봇에게 ai 캐시를 우선 서빙 */
|
|
30
|
-
aiRender?: boolean;
|
|
31
|
-
/** OCR 활성화 (기본: true). AI 워밍 요청 시 OCR 포함 여부 */
|
|
32
|
-
ocr?: boolean;
|
|
33
|
-
/** AI 렌더 경로 prefix (빈 배열 = 전체 경로) */
|
|
34
|
-
aiPathPrefixes?: string[];
|
|
35
|
-
}
|
|
36
|
-
/**
|
|
37
|
-
* Cloudflare Worker에서 봇 요청을 KV 캐시로 프록시.
|
|
38
|
-
* 봇이 아니거나 캐시 미스면 null 반환.
|
|
39
|
-
*
|
|
40
|
-
* AI 봇: ai 캐시 → desktop 폴백 → null (origin)
|
|
41
|
-
* 일반 봇: desktop/mobile 캐시 → null (origin)
|
|
42
|
-
*/
|
|
43
|
-
declare function cloudflareProxy(request: Request, env: {
|
|
44
|
-
V2_CACHE?: KVNamespace;
|
|
45
|
-
[key: string]: unknown;
|
|
46
|
-
}, ctx: ExecutionContext, options: CloudflareProxyOptions): Promise<Response | null>;
|
|
47
|
-
|
|
48
|
-
export { type CloudflareProxyOptions, type NextjsProxyOptions, cloudflareProxy, nextjsProxy };
|
|
1
|
+
export { NextjsProxyOptions, nextjsProxy } from './nextjs.cjs';
|
|
2
|
+
export { CloudflareProxyOptions, cloudflareProxy } from './cloudflare.cjs';
|
package/dist/index.d.ts
CHANGED
|
@@ -1,48 +1,2 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
siteDomain: string;
|
|
4
|
-
cloudfrontDomain: string;
|
|
5
|
-
prerenderDomain: string;
|
|
6
|
-
botLogEndpoint: string;
|
|
7
|
-
/** AI 렌더 활성화 (기본: true). true면 AI 봇에게 ai 캐시를 우선 서빙 */
|
|
8
|
-
aiRender?: boolean;
|
|
9
|
-
/** OCR 활성화 (기본: true). AI 워밍 요청 시 OCR 포함 여부 */
|
|
10
|
-
ocr?: boolean;
|
|
11
|
-
/** AI 렌더 경로 prefix (빈 배열 = 전체 경로) */
|
|
12
|
-
aiPathPrefixes?: string[];
|
|
13
|
-
}
|
|
14
|
-
/**
|
|
15
|
-
* Next.js middleware에서 봇 요청을 CloudFront 캐시로 프록시.
|
|
16
|
-
* 봇이 아니거나 캐시 미스면 null 반환.
|
|
17
|
-
*
|
|
18
|
-
* AI 봇: ai 캐시 → desktop 폴백 → null (origin)
|
|
19
|
-
* 일반 봇: desktop/mobile 캐시 → null (origin)
|
|
20
|
-
*/
|
|
21
|
-
declare function nextjsProxy(request: Request, options: NextjsProxyOptions): Promise<Response | null>;
|
|
22
|
-
|
|
23
|
-
interface CloudflareProxyOptions {
|
|
24
|
-
projectId: string;
|
|
25
|
-
/** 사이트 도메인 (예: "example.com") */
|
|
26
|
-
siteDomain: string;
|
|
27
|
-
prerenderDomain: string;
|
|
28
|
-
botLogEndpoint: string;
|
|
29
|
-
/** AI 렌더 활성화 (기본: true). true면 AI 봇에게 ai 캐시를 우선 서빙 */
|
|
30
|
-
aiRender?: boolean;
|
|
31
|
-
/** OCR 활성화 (기본: true). AI 워밍 요청 시 OCR 포함 여부 */
|
|
32
|
-
ocr?: boolean;
|
|
33
|
-
/** AI 렌더 경로 prefix (빈 배열 = 전체 경로) */
|
|
34
|
-
aiPathPrefixes?: string[];
|
|
35
|
-
}
|
|
36
|
-
/**
|
|
37
|
-
* Cloudflare Worker에서 봇 요청을 KV 캐시로 프록시.
|
|
38
|
-
* 봇이 아니거나 캐시 미스면 null 반환.
|
|
39
|
-
*
|
|
40
|
-
* AI 봇: ai 캐시 → desktop 폴백 → null (origin)
|
|
41
|
-
* 일반 봇: desktop/mobile 캐시 → null (origin)
|
|
42
|
-
*/
|
|
43
|
-
declare function cloudflareProxy(request: Request, env: {
|
|
44
|
-
V2_CACHE?: KVNamespace;
|
|
45
|
-
[key: string]: unknown;
|
|
46
|
-
}, ctx: ExecutionContext, options: CloudflareProxyOptions): Promise<Response | null>;
|
|
47
|
-
|
|
48
|
-
export { type CloudflareProxyOptions, type NextjsProxyOptions, cloudflareProxy, nextjsProxy };
|
|
1
|
+
export { NextjsProxyOptions, nextjsProxy } from './nextjs.js';
|
|
2
|
+
export { CloudflareProxyOptions, cloudflareProxy } from './cloudflare.js';
|
package/dist/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
import{a as o}from"./chunk-HLBLRAGQ.js";import{a as r}from"./chunk-3GWBNF6R.js";import"./chunk-62QI7OUQ.js";export{o as cloudflareProxy,r as nextjsProxy};
|
package/dist/nextjs.cjs
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";var D=Object.create;var f=Object.defineProperty;var H=Object.getOwnPropertyDescriptor;var M=Object.getOwnPropertyNames;var X=Object.getPrototypeOf,z=Object.prototype.hasOwnProperty;var J=(e,o)=>{for(var t in o)f(e,t,{get:o[t],enumerable:!0})},I=(e,o,t,n)=>{if(o&&typeof o=="object"||typeof o=="function")for(let r of M(o))!z.call(e,r)&&r!==t&&f(e,r,{get:()=>o[r],enumerable:!(n=H(o,r))||n.enumerable});return e};var W=(e,o,t)=>(t=e!=null?D(X(e)):{},I(o||!e||!e.__esModule?f(t,"default",{value:e,enumerable:!0}):t,e)),G=e=>I(f({},"__esModule",{value:!0}),e);var tt={};J(tt,{nextjsProxy:()=>L});module.exports=G(tt);var _=["chatgpt-user","claude-user","perplexity-user","gemini-user","gemini-deep-research","mistralai-user","grok-user"],j=["gptbot","oai-searchbot","claudebot","claude-searchbot","google-extended","google-cloudvertexbot","perplexitybot","meta-externalagent","applebot-extended","amazonbot","cohere-ai","bytespider","deepseekbot","grokbot","ccbot","diffbot","ai2bot","petalbot"],k=["googlebot","googlebot-image","googlebot-video","googlebot-news","googleother","mediapartners-google","adsbot-google","google-inspectiontool","bingbot","bingpreview","naverbot","yeti","daumoa","baiduspider","yandexbot","duckduckbot","applebot"],A=["facebookexternalhit","linkedinbot","twitterbot","slackbot","discordbot","telegrambot","whatsapp","pinterestbot","redditbot"],B=["ahrefsbot","semrushbot","mj12bot","dotbot","dataforseobot"],q=["uptimerobot","lighthouse","chrome-lighthouse"],N=new Set([..._,...j]),F=new Set(_),V=[..._,...j,...k,...A,...B,...q];function P(e){let o=e.toLowerCase();for(let t of V)if(o.includes(t)){let n;return F.has(t)?n="ai-user":N.has(t)?n="ai-crawl":k.includes(t)?n="search":A.includes(t)?n="sns":B.includes(t)?n="seo":n="monitoring",{name:t,isAi:N.has(t),category:n}}return null}async function Q(e){if(typeof process<"u"&&process.versions?.node){let{createHash:n}=require("crypto");return n("md5").update(e,"utf8").digest("hex")}let o=new TextEncoder().encode(e),t=await crypto.subtle.digest("MD5",o);return Array.from(new Uint8Array(t),n=>n.toString(16).padStart(2,"0")).join("")}function Y(e){if(!e)return"/";if(e.startsWith("http://")||e.startsWith("https://"))try{e=new URL(e).pathname}catch{}let o=e.indexOf("?");return o!==-1&&(e=e.substring(0,o)),e?e.split("/").map(t=>{if(!t)return t;try{return encodeURIComponent(decodeURIComponent(t))}catch{return encodeURIComponent(t)}}).join("/"):"/"}async function b(e,o){let t=Y(e);return`${await Q(t)}_${o}`}var K=/^\/(?:robots\.txt|llms\.txt|sitemap[^\/]*\.(?:xml|xsl))$/i,Z=/mobile|android|iphone|phone|tablet|webos|ipad/i;async function L(e,o){let{projectId:t,cloudfrontDomain:n,prerenderDomain:r,botLogEndpoint:i,aiRender:x=!0,ocr:y=!0,aiPathPrefixes:T=[]}=o,a=o.siteDomain.replace(/^https?:\/\//,"").replace(/\/+$/,""),w=n.replace(/\/$/,""),d=new URL(e.url),s=d.pathname;if(e.headers.get("x-prerender-host")){if(K.test(s)||s===`/${t}.txt`){let{NextResponse:c}=await import("next/server");return c.next()}return null}if(s===`/${t}.txt`)try{let c=await fetch(`${r}${s}`,{redirect:"manual"});return new Response(c.body,{status:c.status,headers:{"Content-Type":"text/plain","Cache-Control":"public, max-age=3600"}})}catch{return null}if(K.test(s))try{let c=await fetch(`${r}/static${s}`,{headers:{"X-Signature":t,"X-Original-Host":a}});return new Response(c.body,{status:c.status,headers:{"Content-Type":c.headers.get("Content-Type")||"text/plain","Cache-Control":"public, max-age=3600"}})}catch{return null}let p=e.headers.get("user-agent")||"",g=P(p);if(!g)return null;let v=Z.test(p)?"mobile":"desktop",h=`https://${a}${s}`;try{if(g.isAi&&x){let u=await b(s,"ai"),R=await fetch(`${w}/v2/${a}/${u}.html`,{headers:{Accept:"text/html"}});if(R.ok){let l=await R.text();if(l&&l.length>100)return m(i,t,a,s,d.search,p,"hit_ai"),$(r,t,h,y,T),O(l,"HIT-AI",g.name)}let U=await b(s,"desktop"),E=await fetch(`${w}/v2/${a}/${U}.html`,{headers:{Accept:"text/html"}});if(E.ok){let l=await E.text();if(l&&l.length>100)return m(i,t,a,s,d.search,p,"hit_desktop_fallback"),$(r,t,h,y,T),O(l,"HIT-DESKTOP",g.name)}return m(i,t,a,s,d.search,p,"miss_ai"),$(r,t,h,y,T),S(r,t,h),null}let c=await b(s,v),C=await fetch(`${w}/v2/${a}/${c}.html`,{headers:{Accept:"text/html"}});if(C.ok){let u=await C.text();if(u&&u.length>100)return m(i,t,a,s,d.search,p,"hit"),S(r,t,h),O(u,"HIT",g.name)}}catch{}return m(i,t,a,s,d.search,p,"miss"),S(r,t,h),null}function O(e,o,t){return new Response(e,{headers:{"Content-Type":"text/html; charset=utf-8","X-Cache":o,"X-Bot":t}})}function m(e,o,t,n,r,i,x){fetch(e,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({project_id:o,url:`https://${t}${n}${r}`,domain:t,path:n,user_agent:i,phase:x})}).catch(()=>{})}function S(e,o,t){fetch(`${e}/v2/cache`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({items:[{url:t,project_id:o}]})}).catch(()=>{})}function $(e,o,t,n,r){let i={items:[{url:t,project_id:o}],ocr:n};r.length>0&&(i.path_prefixes=r),fetch(`${e}/v2/cache/ai`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(i)}).catch(()=>{})}0&&(module.exports={nextjsProxy});
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
interface NextjsProxyOptions {
|
|
2
|
+
projectId: string;
|
|
3
|
+
siteDomain: string;
|
|
4
|
+
cloudfrontDomain: string;
|
|
5
|
+
prerenderDomain: string;
|
|
6
|
+
botLogEndpoint: string;
|
|
7
|
+
/** AI 렌더 활성화 (기본: true). true면 AI 봇에게 ai 캐시를 우선 서빙 */
|
|
8
|
+
aiRender?: boolean;
|
|
9
|
+
/** OCR 활성화 (기본: true). AI 워밍 요청 시 OCR 포함 여부 */
|
|
10
|
+
ocr?: boolean;
|
|
11
|
+
/** AI 렌더 경로 prefix (빈 배열 = 전체 경로) */
|
|
12
|
+
aiPathPrefixes?: string[];
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Next.js middleware에서 봇 요청을 CloudFront 캐시로 프록시.
|
|
16
|
+
* 봇이 아니거나 캐시 미스면 null 반환.
|
|
17
|
+
*
|
|
18
|
+
* AI 봇: ai 캐시 → desktop 폴백 → null (origin)
|
|
19
|
+
* 일반 봇: desktop/mobile 캐시 → null (origin)
|
|
20
|
+
*/
|
|
21
|
+
declare function nextjsProxy(request: Request, options: NextjsProxyOptions): Promise<Response | null>;
|
|
22
|
+
|
|
23
|
+
export { type NextjsProxyOptions, nextjsProxy };
|
package/dist/nextjs.d.ts
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
interface NextjsProxyOptions {
|
|
2
|
+
projectId: string;
|
|
3
|
+
siteDomain: string;
|
|
4
|
+
cloudfrontDomain: string;
|
|
5
|
+
prerenderDomain: string;
|
|
6
|
+
botLogEndpoint: string;
|
|
7
|
+
/** AI 렌더 활성화 (기본: true). true면 AI 봇에게 ai 캐시를 우선 서빙 */
|
|
8
|
+
aiRender?: boolean;
|
|
9
|
+
/** OCR 활성화 (기본: true). AI 워밍 요청 시 OCR 포함 여부 */
|
|
10
|
+
ocr?: boolean;
|
|
11
|
+
/** AI 렌더 경로 prefix (빈 배열 = 전체 경로) */
|
|
12
|
+
aiPathPrefixes?: string[];
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Next.js middleware에서 봇 요청을 CloudFront 캐시로 프록시.
|
|
16
|
+
* 봇이 아니거나 캐시 미스면 null 반환.
|
|
17
|
+
*
|
|
18
|
+
* AI 봇: ai 캐시 → desktop 폴백 → null (origin)
|
|
19
|
+
* 일반 봇: desktop/mobile 캐시 → null (origin)
|
|
20
|
+
*/
|
|
21
|
+
declare function nextjsProxy(request: Request, options: NextjsProxyOptions): Promise<Response | null>;
|
|
22
|
+
|
|
23
|
+
export { type NextjsProxyOptions, nextjsProxy };
|
package/dist/nextjs.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{a as o}from"./chunk-3GWBNF6R.js";import"./chunk-62QI7OUQ.js";export{o as nextjsProxy};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@searchos/bot-proxy",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.4",
|
|
4
4
|
"description": "SearchOS 봇 프록시 — Next.js, Cloudflare Worker용 봇 감지 + 캐시 프록시",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
@@ -8,6 +8,16 @@
|
|
|
8
8
|
"types": "./dist/index.d.ts",
|
|
9
9
|
"import": "./dist/index.js",
|
|
10
10
|
"require": "./dist/index.cjs"
|
|
11
|
+
},
|
|
12
|
+
"./nextjs": {
|
|
13
|
+
"types": "./dist/nextjs.d.ts",
|
|
14
|
+
"import": "./dist/nextjs.js",
|
|
15
|
+
"require": "./dist/nextjs.cjs"
|
|
16
|
+
},
|
|
17
|
+
"./cloudflare": {
|
|
18
|
+
"types": "./dist/cloudflare.d.ts",
|
|
19
|
+
"import": "./dist/cloudflare.js",
|
|
20
|
+
"require": "./dist/cloudflare.cjs"
|
|
11
21
|
}
|
|
12
22
|
},
|
|
13
23
|
"main": "dist/index.cjs",
|
|
@@ -17,7 +27,7 @@
|
|
|
17
27
|
"dist"
|
|
18
28
|
],
|
|
19
29
|
"scripts": {
|
|
20
|
-
"build": "tsup src/index.ts --format esm,cjs --dts --clean --minify",
|
|
30
|
+
"build": "tsup src/index.ts src/nextjs.ts src/cloudflare.ts --format esm,cjs --dts --clean --minify",
|
|
21
31
|
"prepublishOnly": "npm run build"
|
|
22
32
|
},
|
|
23
33
|
"devDependencies": {
|