@netloc8/nextjs 1.0.1 → 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.
@@ -1 +1 @@
1
- {"version":3,"file":"proxy.d.mts","names":[],"sources":["../src/proxy.ts"],"mappings":";;;;UAmBU,kBAAA;EACN,OAAA;EACA,MAAA;EACA,MAAA;EACA,MAAA;EACA,OAAA,IACI,OAAA,EAAS,WAAA,EACT,GAAA,EAAK,GAAA,KACJ,YAAA,eAA2B,OAAA,CAAQ,YAAA;AAAA;AAAA,UAGlC,kBAAA;EACN,aAAA;EACA,SAAA,EAAW,MAAA;EACX,YAAA;AAAA;;;;;iBAiPY,cAAA,CAAe,OAAA,EAAS,OAAA,GAAU,GAAA;;;;;;;;iBA2BlC,WAAA,CAAY,OAAA,GAAU,kBAAA,IACjC,OAAA,EAAS,WAAA,KAAgB,OAAA,CAAQ,YAAA;AAnRM;;;AAAA,iBAkY5B,eAAA,CACZ,OAAA,EAAS,kBAAA,IACT,OAAA,EAAS,WAAA,EAAa,GAAA,EAAK,GAAA,KAAQ,YAAA"}
1
+ {"version":3,"file":"proxy.d.mts","names":[],"sources":["../src/proxy.ts"],"mappings":";;;;UAmBU,kBAAA;EACN,OAAA;EACA,MAAA;EACA,MAAA;EACA,MAAA;EACA,OAAA,IACI,OAAA,EAAS,WAAA,EACT,GAAA,EAAK,GAAA,KACJ,YAAA,eAA2B,OAAA,CAAQ,YAAA;AAAA;AAAA,UAGlC,kBAAA;EACN,aAAA;EACA,SAAA,EAAW,MAAA;EACX,YAAA;AAAA;;;;;iBAiPY,cAAA,CAAe,OAAA,EAAS,OAAA,GAAU,GAAA;;;;;;;;iBA2BlC,WAAA,CAAY,OAAA,GAAU,kBAAA,IACjC,OAAA,EAAS,WAAA,KAAgB,OAAA,CAAQ,YAAA;AAnRM;;;AAAA,iBAia5B,eAAA,CACZ,OAAA,EAAS,kBAAA,IACT,OAAA,EAAS,WAAA,EAAa,GAAA,EAAK,GAAA,KAAQ,YAAA"}
package/dist/proxy.mjs CHANGED
@@ -1,2 +1,4 @@
1
- import{NextResponse as e}from"next/server";import{COOKIE_NAME as t,COOKIE_OPTIONS as n,fetchGeo as r,getClientIp as i,getGeoFromPlatformHeaders as a,isPublicIp as o,normalizeApiResponse as s,parseCookie as c,reconcileGeo as l,serializeCookie as u}from"@netloc8/core";const d=[{header:`x-netloc8-ip`,get:e=>e.query?.value,set:(e,t)=>{e.query||={},e.query.value=t},type:`string`},{header:`x-netloc8-ip-version`,get:e=>e.query?.ipVersion,set:(e,t)=>{let n=parseFloat(t);Number.isFinite(n)&&(e.query||={},e.query.ipVersion=n)},type:`number`},{header:`x-netloc8-continent-code`,get:e=>e.location?.continent?.code,set:(e,t)=>{e.location||={},e.location.continent||(e.location.continent={}),e.location.continent.code=t},type:`string`},{header:`x-netloc8-continent-name`,get:e=>e.location?.continent?.name,set:(e,t)=>{e.location||={},e.location.continent||(e.location.continent={}),e.location.continent.name=t},type:`string`},{header:`x-netloc8-country-code`,get:e=>e.location?.country?.code,set:(e,t)=>{e.location||={},e.location.country||(e.location.country={}),e.location.country.code=t},type:`string`},{header:`x-netloc8-country-name`,get:e=>e.location?.country?.name,set:(e,t)=>{e.location||={},e.location.country||(e.location.country={}),e.location.country.name=t},type:`string`},{header:`x-netloc8-country-flag`,get:e=>e.location?.country?.flag,set:(e,t)=>{e.location||={},e.location.country||(e.location.country={}),e.location.country.flag=t},type:`string`},{header:`x-netloc8-country-unions`,get:e=>e.location?.country?.unions,set:(e,t)=>{e.location||={},e.location.country||(e.location.country={});try{let n=JSON.parse(t);Array.isArray(n)&&(e.location.country.unions=n)}catch{}},type:`json`},{header:`x-netloc8-region-code`,get:e=>e.location?.region?.code,set:(e,t)=>{e.location||={},e.location.region||(e.location.region={}),e.location.region.code=t},type:`string`},{header:`x-netloc8-region-name`,get:e=>e.location?.region?.name,set:(e,t)=>{e.location||={},e.location.region||(e.location.region={}),e.location.region.name=t},type:`string`},{header:`x-netloc8-district`,get:e=>e.location?.district,set:(e,t)=>{e.location||={},e.location.district=t},type:`string`},{header:`x-netloc8-city`,get:e=>e.location?.city,set:(e,t)=>{e.location||={},e.location.city=t},type:`string`},{header:`x-netloc8-postal-code`,get:e=>e.location?.postalCode,set:(e,t)=>{e.location||={},e.location.postalCode=t},type:`string`},{header:`x-netloc8-latitude`,get:e=>e.location?.coordinates?.latitude,set:(e,t)=>{e.location||={},e.location.coordinates||(e.location.coordinates={});let n=parseFloat(t);Number.isFinite(n)&&(e.location.coordinates.latitude=n)},type:`number`},{header:`x-netloc8-longitude`,get:e=>e.location?.coordinates?.longitude,set:(e,t)=>{e.location||={},e.location.coordinates||(e.location.coordinates={});let n=parseFloat(t);Number.isFinite(n)&&(e.location.coordinates.longitude=n)},type:`number`},{header:`x-netloc8-accuracy-radius`,get:e=>e.location?.coordinates?.accuracyRadius,set:(e,t)=>{e.location||={},e.location.coordinates||(e.location.coordinates={});let n=parseFloat(t);Number.isFinite(n)&&(e.location.coordinates.accuracyRadius=n)},type:`number`},{header:`x-netloc8-timezone`,get:e=>e.location?.timezone,set:(e,t)=>{e.location||={},e.location.timezone=t},type:`string`},{header:`x-netloc8-utc-offset`,get:e=>e.location?.utcOffset,set:(e,t)=>{e.location||={},e.location.utcOffset=t},type:`string`},{header:`x-netloc8-geo-confidence`,get:e=>e.location?.geoConfidence,set:(e,t)=>{let n=parseFloat(t);Number.isFinite(n)&&(e.location||={},e.location.geoConfidence=n)},type:`number`},{header:`x-netloc8-asn`,get:e=>e.network?.asn,set:(e,t)=>{e.network||={},e.network.asn=t},type:`string`},{header:`x-netloc8-asn-org`,get:e=>e.network?.organization,set:(e,t)=>{e.network||={},e.network.organization=t},type:`string`},{header:`x-netloc8-asn-domain`,get:e=>e.network?.domain,set:(e,t)=>{e.network||={},e.network.domain=t},type:`string`},{header:`x-netloc8-precision`,get:e=>e.meta?.precision,set:(e,t)=>{e.meta||={},e.meta.precision=t},type:`string`},{header:`x-netloc8-degraded`,get:e=>e.meta?.degraded,set:(e,t)=>{e.meta||={},e.meta.degraded=t===`true`},type:`boolean`},{header:`x-netloc8-timezone-from-client`,get:e=>e.location?.timezoneFromClient,set:(e,t)=>{e.location||={},e.location.timezoneFromClient=t===`true`},type:`boolean`}];function f(e,t){for(let n of d){let r=n.get(t);r!=null&&(n.type===`json`?e.set(n.header,encodeURIComponent(JSON.stringify(r))):e.set(n.header,encodeURIComponent(String(r))))}}function p(e){let t={};for(let n of d){let r=e.get(n.header);if(r!==null)try{let e=decodeURIComponent(r);n.set(t,e)}catch{}}return t}function m(p){return async m=>{let h=p?.apiKey??process.env.NETLOC8_API_KEY,g=p?.apiUrl??process.env.NETLOC8_API_URL,_=p?.timeout??1500,v=new Headers(m.headers);for(let e of d)v.delete(e.header);let y;process.env.NODE_ENV!==`production`&&(y=p?.testIp??process.env.NETLOC8_TEST_IP),y||=i(m.headers);let b=m.cookies.get(t)?.value,x=c(b),S=x.location?.timezoneFromClient===!0&&x.query?.value===y?{timezone:x.location.timezone,timezoneFromClient:x.location.timezoneFromClient}:void 0,C=a(m.headers),w;if(y&&o(y)&&!C.location?.country?.code&&!S){let e=await r(y,{apiKey:h,apiUrl:g,timeout:_,clientId:`@netloc8/nextjs/1.0.1`});e&&(w=s(e,y))}let T=l({cookie:x.query?.value?x:void 0,platform:C,api:w,ip:y});S&&(T.location||={},T.location.timezone=S.timezone,T.location.timezoneFromClient=S.timezoneFromClient),f(v,T);let E;if(p?.handler){let e=new Request(m.nextUrl.toString(),{method:m.method??`GET`,headers:v,body:m.body,duplex:`half`});E=await p.handler(Object.assign(e,{nextUrl:m.nextUrl,cookies:m.cookies}),T)}let D=E??e.next({request:{headers:v}});return(!b||x.query?.value!==y)&&D.cookies.set(t,u(T),{path:n.path,httpOnly:n.httpOnly,secure:n.secure,sameSite:n.sameSite,maxAge:n.maxAge}),D}}function h(t){let{defaultLocale:n,localeMap:r,excludePaths:i=[]}=t,a=new Set(Object.values(r));return a.add(n),(t,o)=>{let s=t.nextUrl.pathname;for(let e of i)if(s.startsWith(e))return;let c=s.split(`/`).filter(Boolean)[0];if(c&&a.has(c))return;let l=o.location?.country?.code,u=l&&r[l]||n;if(u===n)return;let d=t.nextUrl.clone();return d.pathname=`/${u}${s}`,e.redirect(d,307)}}export{m as createProxy,p as readGeoHeaders,h as withGeoRedirect};
1
+ import{NextResponse as e}from"next/server";import{COOKIE_NAME as t,COOKIE_OPTIONS as n,fetchGeo as r,getClientIp as i,getGeoFromPlatformHeaders as a,isPublicIp as o,normalizeApiResponse as s,parseCookie as c,reconcileGeo as l,serializeCookie as u}from"@netloc8/core";const d=[{header:`x-netloc8-ip`,get:e=>e.query?.value,set:(e,t)=>{e.query||={},e.query.value=t},type:`string`},{header:`x-netloc8-ip-version`,get:e=>e.query?.ipVersion,set:(e,t)=>{let n=parseFloat(t);Number.isFinite(n)&&(e.query||={},e.query.ipVersion=n)},type:`number`},{header:`x-netloc8-continent-code`,get:e=>e.location?.continent?.code,set:(e,t)=>{e.location||={},e.location.continent||(e.location.continent={}),e.location.continent.code=t},type:`string`},{header:`x-netloc8-continent-name`,get:e=>e.location?.continent?.name,set:(e,t)=>{e.location||={},e.location.continent||(e.location.continent={}),e.location.continent.name=t},type:`string`},{header:`x-netloc8-country-code`,get:e=>e.location?.country?.code,set:(e,t)=>{e.location||={},e.location.country||(e.location.country={}),e.location.country.code=t},type:`string`},{header:`x-netloc8-country-name`,get:e=>e.location?.country?.name,set:(e,t)=>{e.location||={},e.location.country||(e.location.country={}),e.location.country.name=t},type:`string`},{header:`x-netloc8-country-flag`,get:e=>e.location?.country?.flag,set:(e,t)=>{e.location||={},e.location.country||(e.location.country={}),e.location.country.flag=t},type:`string`},{header:`x-netloc8-country-unions`,get:e=>e.location?.country?.unions,set:(e,t)=>{e.location||={},e.location.country||(e.location.country={});try{let n=JSON.parse(t);Array.isArray(n)&&(e.location.country.unions=n)}catch{}},type:`json`},{header:`x-netloc8-region-code`,get:e=>e.location?.region?.code,set:(e,t)=>{e.location||={},e.location.region||(e.location.region={}),e.location.region.code=t},type:`string`},{header:`x-netloc8-region-name`,get:e=>e.location?.region?.name,set:(e,t)=>{e.location||={},e.location.region||(e.location.region={}),e.location.region.name=t},type:`string`},{header:`x-netloc8-district`,get:e=>e.location?.district,set:(e,t)=>{e.location||={},e.location.district=t},type:`string`},{header:`x-netloc8-city`,get:e=>e.location?.city,set:(e,t)=>{e.location||={},e.location.city=t},type:`string`},{header:`x-netloc8-postal-code`,get:e=>e.location?.postalCode,set:(e,t)=>{e.location||={},e.location.postalCode=t},type:`string`},{header:`x-netloc8-latitude`,get:e=>e.location?.coordinates?.latitude,set:(e,t)=>{e.location||={},e.location.coordinates||(e.location.coordinates={});let n=parseFloat(t);Number.isFinite(n)&&(e.location.coordinates.latitude=n)},type:`number`},{header:`x-netloc8-longitude`,get:e=>e.location?.coordinates?.longitude,set:(e,t)=>{e.location||={},e.location.coordinates||(e.location.coordinates={});let n=parseFloat(t);Number.isFinite(n)&&(e.location.coordinates.longitude=n)},type:`number`},{header:`x-netloc8-accuracy-radius`,get:e=>e.location?.coordinates?.accuracyRadius,set:(e,t)=>{e.location||={},e.location.coordinates||(e.location.coordinates={});let n=parseFloat(t);Number.isFinite(n)&&(e.location.coordinates.accuracyRadius=n)},type:`number`},{header:`x-netloc8-timezone`,get:e=>e.location?.timezone,set:(e,t)=>{e.location||={},e.location.timezone=t},type:`string`},{header:`x-netloc8-utc-offset`,get:e=>e.location?.utcOffset,set:(e,t)=>{e.location||={},e.location.utcOffset=t},type:`string`},{header:`x-netloc8-geo-confidence`,get:e=>e.location?.geoConfidence,set:(e,t)=>{let n=parseFloat(t);Number.isFinite(n)&&(e.location||={},e.location.geoConfidence=n)},type:`number`},{header:`x-netloc8-asn`,get:e=>e.network?.asn,set:(e,t)=>{e.network||={},e.network.asn=t},type:`string`},{header:`x-netloc8-asn-org`,get:e=>e.network?.organization,set:(e,t)=>{e.network||={},e.network.organization=t},type:`string`},{header:`x-netloc8-asn-domain`,get:e=>e.network?.domain,set:(e,t)=>{e.network||={},e.network.domain=t},type:`string`},{header:`x-netloc8-precision`,get:e=>e.meta?.precision,set:(e,t)=>{e.meta||={},e.meta.precision=t},type:`string`},{header:`x-netloc8-degraded`,get:e=>e.meta?.degraded,set:(e,t)=>{e.meta||={},e.meta.degraded=t===`true`},type:`boolean`},{header:`x-netloc8-timezone-from-client`,get:e=>e.location?.timezoneFromClient,set:(e,t)=>{e.location||={},e.location.timezoneFromClient=t===`true`},type:`boolean`}];function f(e,t){for(let n of d){let r=n.get(t);r!=null&&(n.type===`json`?e.set(n.header,encodeURIComponent(JSON.stringify(r))):e.set(n.header,encodeURIComponent(String(r))))}}function p(e){let t={};for(let n of d){let r=e.get(n.header);if(r!==null)try{let e=decodeURIComponent(r);n.set(t,e)}catch{}}return t}function m(p){return async m=>{let h=p?.apiKey??process.env.NETLOC8_API_KEY,g=p?.apiUrl??process.env.NETLOC8_API_URL,_=p?.timeout??1500,v=`@netloc8/nextjs/1.1.0`,y=new Headers(m.headers);for(let e of d)y.delete(e.header);let b;process.env.NODE_ENV!==`production`&&(b=p?.testIp??process.env.NETLOC8_TEST_IP),b||=i(m.headers);let x=m.cookies.get(t)?.value,S=c(x),C=S.location?.timezoneFromClient===!0&&S.query?.value===b?{timezone:S.location.timezone,timezoneFromClient:S.location.timezoneFromClient}:void 0,w=a(m.headers),T=S.query?.value!==b,E;if(process.env.NODE_ENV!==`production`&&!h&&T&&(w.location?.country?.code?console.warn(`[netloc8] No API key configured using platform headers only (country-level).
2
+ Get a free key at https://netloc8.com for city-level geo.`):console.warn(`[netloc8] No API key configured and no platform geo headers detected.
3
+ A free API key enables faster geo responses. Get one at https://netloc8.com`)),b&&o(b)&&T)if(h){let e=await r(b,{apiKey:h,apiUrl:g,timeout:_,clientId:v});e&&(E=s(e,b))}else r(b,{apiUrl:g,timeout:100,clientId:v,allowAnonymous:!0}).catch(()=>{});let D=l({cookie:S.query?.value?S:void 0,platform:w,api:E,ip:b});C&&(D.location||={},D.location.timezone=C.timezone,D.location.timezoneFromClient=C.timezoneFromClient),f(y,D);let O;if(p?.handler){let e=new Request(m.nextUrl.toString(),{method:m.method??`GET`,headers:y,body:m.body,duplex:`half`});O=await p.handler(Object.assign(e,{nextUrl:m.nextUrl,cookies:m.cookies}),D)}let k=O??e.next({request:{headers:y}});return(!x||T)&&k.cookies.set(t,u(D),{path:n.path,httpOnly:n.httpOnly,secure:n.secure,sameSite:n.sameSite,maxAge:n.maxAge}),k}}function h(t){let{defaultLocale:n,localeMap:r,excludePaths:i=[]}=t,a=new Set(Object.values(r));return a.add(n),(t,o)=>{let s=t.nextUrl.pathname;for(let e of i)if(s.startsWith(e))return;let c=s.split(`/`).filter(Boolean)[0];if(c&&a.has(c))return;let l=o.location?.country?.code,u=l&&r[l]||n;if(u===n)return;let d=t.nextUrl.clone();return d.pathname=`/${u}${s}`,e.redirect(d,307)}}export{m as createProxy,p as readGeoHeaders,h as withGeoRedirect};
2
4
  //# sourceMappingURL=proxy.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"proxy.mjs","names":[],"sources":["../src/proxy.ts"],"sourcesContent":["declare const __PKG_NAME__: string;\ndeclare const __PKG_VERSION__: string;\n\nimport type { Geo } from '@netloc8/core';\nimport type { NextRequest } from 'next/server';\nimport { NextResponse } from 'next/server';\nimport {\n getClientIp,\n isPublicIp,\n getGeoFromPlatformHeaders,\n fetchGeo,\n normalizeApiResponse,\n parseCookie,\n serializeCookie,\n reconcileGeo,\n COOKIE_NAME,\n COOKIE_OPTIONS,\n} from '@netloc8/core';\n\ninterface CreateProxyOptions {\n timeout?: number;\n apiKey?: string;\n apiUrl?: string;\n testIp?: string;\n handler?: (\n request: NextRequest,\n geo: Geo\n ) => NextResponse | undefined | Promise<NextResponse | undefined>;\n}\n\ninterface GeoRedirectOptions {\n defaultLocale: string;\n localeMap: Record<string, string>;\n excludePaths?: string[];\n}\n\n// --- Header transport ---\n// These map nested Geo paths to/from x-netloc8-* request headers\n// for the proxy → Server Component transport layer.\n\ninterface HeaderEntry {\n header: string;\n get: (geo: Geo) => string | number | boolean | string[] | undefined;\n set: (geo: Geo, raw: string) => void;\n type: 'string' | 'number' | 'boolean' | 'json';\n}\n\nconst HEADER_ENTRIES: HeaderEntry[] = [\n {\n header: 'x-netloc8-ip',\n get: (g) => g.query?.value,\n set: (g, v) => { if (!g.query) g.query = {}; g.query.value = v; },\n type: 'string',\n },\n {\n header: 'x-netloc8-ip-version',\n get: (g) => g.query?.ipVersion,\n set: (g, v) => { const n = parseFloat(v); if (!Number.isFinite(n)) return; if (!g.query) g.query = {}; g.query.ipVersion = n; },\n type: 'number',\n },\n {\n header: 'x-netloc8-continent-code',\n get: (g) => g.location?.continent?.code,\n set: (g, v) => {\n if (!g.location) g.location = {};\n if (!g.location.continent) g.location.continent = {};\n g.location.continent.code = v;\n },\n type: 'string',\n },\n {\n header: 'x-netloc8-continent-name',\n get: (g) => g.location?.continent?.name,\n set: (g, v) => {\n if (!g.location) g.location = {};\n if (!g.location.continent) g.location.continent = {};\n g.location.continent.name = v;\n },\n type: 'string',\n },\n {\n header: 'x-netloc8-country-code',\n get: (g) => g.location?.country?.code,\n set: (g, v) => {\n if (!g.location) g.location = {};\n if (!g.location.country) g.location.country = {};\n g.location.country.code = v;\n },\n type: 'string',\n },\n {\n header: 'x-netloc8-country-name',\n get: (g) => g.location?.country?.name,\n set: (g, v) => {\n if (!g.location) g.location = {};\n if (!g.location.country) g.location.country = {};\n g.location.country.name = v;\n },\n type: 'string',\n },\n {\n header: 'x-netloc8-country-flag',\n get: (g) => g.location?.country?.flag,\n set: (g, v) => {\n if (!g.location) g.location = {};\n if (!g.location.country) g.location.country = {};\n g.location.country.flag = v;\n },\n type: 'string',\n },\n {\n header: 'x-netloc8-country-unions',\n get: (g) => g.location?.country?.unions,\n set: (g, v) => {\n if (!g.location) g.location = {};\n if (!g.location.country) g.location.country = {};\n try {\n const parsed = JSON.parse(v);\n if (Array.isArray(parsed)) {\n g.location.country.unions = parsed;\n }\n } catch {\n // Skip malformed JSON\n }\n },\n type: 'json',\n },\n {\n header: 'x-netloc8-region-code',\n get: (g) => g.location?.region?.code,\n set: (g, v) => {\n if (!g.location) g.location = {};\n if (!g.location.region) g.location.region = {};\n g.location.region.code = v;\n },\n type: 'string',\n },\n {\n header: 'x-netloc8-region-name',\n get: (g) => g.location?.region?.name,\n set: (g, v) => {\n if (!g.location) g.location = {};\n if (!g.location.region) g.location.region = {};\n g.location.region.name = v;\n },\n type: 'string',\n },\n {\n header: 'x-netloc8-district',\n get: (g) => g.location?.district,\n set: (g, v) => { if (!g.location) g.location = {}; g.location.district = v; },\n type: 'string',\n },\n {\n header: 'x-netloc8-city',\n get: (g) => g.location?.city,\n set: (g, v) => { if (!g.location) g.location = {}; g.location.city = v; },\n type: 'string',\n },\n {\n header: 'x-netloc8-postal-code',\n get: (g) => g.location?.postalCode,\n set: (g, v) => { if (!g.location) g.location = {}; g.location.postalCode = v; },\n type: 'string',\n },\n {\n header: 'x-netloc8-latitude',\n get: (g) => g.location?.coordinates?.latitude,\n set: (g, v) => {\n if (!g.location) g.location = {};\n if (!g.location.coordinates) g.location.coordinates = {};\n const n = parseFloat(v); if (!Number.isFinite(n)) return;\n g.location.coordinates.latitude = n;\n },\n type: 'number',\n },\n {\n header: 'x-netloc8-longitude',\n get: (g) => g.location?.coordinates?.longitude,\n set: (g, v) => {\n if (!g.location) g.location = {};\n if (!g.location.coordinates) g.location.coordinates = {};\n const n = parseFloat(v); if (!Number.isFinite(n)) return;\n g.location.coordinates.longitude = n;\n },\n type: 'number',\n },\n {\n header: 'x-netloc8-accuracy-radius',\n get: (g) => g.location?.coordinates?.accuracyRadius,\n set: (g, v) => {\n if (!g.location) g.location = {};\n if (!g.location.coordinates) g.location.coordinates = {};\n const n = parseFloat(v); if (!Number.isFinite(n)) return;\n g.location.coordinates.accuracyRadius = n;\n },\n type: 'number',\n },\n {\n header: 'x-netloc8-timezone',\n get: (g) => g.location?.timezone,\n set: (g, v) => { if (!g.location) g.location = {}; g.location.timezone = v; },\n type: 'string',\n },\n {\n header: 'x-netloc8-utc-offset',\n get: (g) => g.location?.utcOffset,\n set: (g, v) => { if (!g.location) g.location = {}; g.location.utcOffset = v; },\n type: 'string',\n },\n {\n header: 'x-netloc8-geo-confidence',\n get: (g) => g.location?.geoConfidence,\n set: (g, v) => { const n = parseFloat(v); if (!Number.isFinite(n)) return; if (!g.location) g.location = {}; g.location.geoConfidence = n; },\n type: 'number',\n },\n {\n header: 'x-netloc8-asn',\n get: (g) => g.network?.asn,\n set: (g, v) => { if (!g.network) g.network = {}; g.network.asn = v; },\n type: 'string',\n },\n {\n header: 'x-netloc8-asn-org',\n get: (g) => g.network?.organization,\n set: (g, v) => { if (!g.network) g.network = {}; g.network.organization = v; },\n type: 'string',\n },\n {\n header: 'x-netloc8-asn-domain',\n get: (g) => g.network?.domain,\n set: (g, v) => { if (!g.network) g.network = {}; g.network.domain = v; },\n type: 'string',\n },\n {\n header: 'x-netloc8-precision',\n get: (g) => g.meta?.precision,\n set: (g, v) => { if (!g.meta) g.meta = {}; g.meta.precision = v; },\n type: 'string',\n },\n {\n header: 'x-netloc8-degraded',\n get: (g) => g.meta?.degraded,\n set: (g, v) => { if (!g.meta) g.meta = {}; g.meta.degraded = v === 'true'; },\n type: 'boolean',\n },\n {\n header: 'x-netloc8-timezone-from-client',\n get: (g) => g.location?.timezoneFromClient,\n set: (g, v) => { if (!g.location) g.location = {}; g.location.timezoneFromClient = v === 'true'; },\n type: 'boolean',\n },\n];\n\n/**\n * Set x-netloc8-* request headers from a Geo object.\n */\nfunction setGeoHeaders(requestHeaders: Headers, geo: Geo): void {\n for (const entry of HEADER_ENTRIES) {\n const value = entry.get(geo);\n if (value !== undefined && value !== null) {\n if (entry.type === 'json') {\n requestHeaders.set(entry.header, encodeURIComponent(JSON.stringify(value)));\n } else {\n requestHeaders.set(entry.header, encodeURIComponent(String(value)));\n }\n }\n }\n}\n\n/**\n * Read x-netloc8-* request headers back into a Geo object.\n * Used by server.ts to reconstruct Geo on the server side.\n */\nexport function readGeoHeaders(headers: Headers): Geo {\n const geo: Geo = {};\n\n for (const entry of HEADER_ENTRIES) {\n const raw = headers.get(entry.header);\n if (raw === null) {\n continue;\n }\n\n try {\n const decoded = decodeURIComponent(raw);\n entry.set(geo, decoded);\n } catch {\n // Skip this header if decodeURIComponent throws\n }\n }\n\n return geo;\n}\n\n/**\n * Create a Next.js 16 proxy function that resolves geolocation for every\n * matching request.\n *\n * Returns a standard proxy function that can be exported directly from the\n * user's proxy.ts / proxy.js file, or composed with other proxy logic.\n */\nexport function createProxy(options?: CreateProxyOptions):\n (request: NextRequest) => Promise<NextResponse> {\n\n return async (request: NextRequest): Promise<NextResponse> => {\n const apiKey = options?.apiKey ?? process.env.NETLOC8_API_KEY;\n const apiUrl = options?.apiUrl ?? process.env.NETLOC8_API_URL;\n const timeout = options?.timeout ?? 1500;\n\n // Security: Remove any incoming spoofed headers\n const requestHeaders = new Headers(request.headers);\n for (const entry of HEADER_ENTRIES) {\n requestHeaders.delete(entry.header);\n }\n\n // 1. Determine client IP\n let clientIp: string | undefined;\n\n if (process.env.NODE_ENV !== 'production') {\n clientIp = options?.testIp ?? process.env.NETLOC8_TEST_IP;\n }\n\n if (!clientIp) {\n clientIp = getClientIp(request.headers);\n }\n\n // 2. Check the cookie cache (fast path)\n const cookieValue = request.cookies.get(COOKIE_NAME)?.value;\n const cookieGeo = parseCookie(cookieValue);\n\n // Cookie fast path: only trust timezone/timezoneFromClient from the\n // client-controlled cookie. Re-resolve other geo fields to prevent\n // spoofing of country/region/city via cookie manipulation.\n const cookieTimezone = (\n cookieGeo.location?.timezoneFromClient === true &&\n cookieGeo.query?.value === clientIp\n ) ? {\n timezone: cookieGeo.location.timezone,\n timezoneFromClient: cookieGeo.location.timezoneFromClient,\n } : undefined;\n\n // 3. Extract platform headers (zero-cost)\n const platformGeo = getGeoFromPlatformHeaders(request.headers);\n\n // 4. Decide whether to call the API\n let apiGeo: Geo | undefined;\n\n if (clientIp && isPublicIp(clientIp) && !platformGeo.location?.country?.code && !cookieTimezone) {\n const raw = await fetchGeo(clientIp, { apiKey, apiUrl, timeout, clientId: typeof __PKG_NAME__ !== 'undefined' ? `${__PKG_NAME__}/${__PKG_VERSION__}` : undefined });\n if (raw) {\n apiGeo = normalizeApiResponse(raw, clientIp);\n }\n }\n\n // 5. Reconcile all sources — cookie is lowest priority in\n // reconcileGeo, so platform headers and API data overwrite it.\n // Pass the full cookie so self-hosted deployments (no platform\n // headers, API call skipped) still have city/country/region.\n const geo = reconcileGeo({\n cookie: cookieGeo.query?.value ? cookieGeo : undefined,\n platform: platformGeo,\n api: apiGeo,\n ip: clientIp,\n });\n\n // Apply trusted cookie timezone if available\n if (cookieTimezone) {\n if (!geo.location) geo.location = {};\n geo.location.timezone = cookieTimezone.timezone;\n geo.location.timezoneFromClient = cookieTimezone.timezoneFromClient;\n }\n\n // 6. Set request headers\n setGeoHeaders(requestHeaders, geo);\n\n // 7. Build the response — use sanitized headers in the handler\n let handlerResponse: NextResponse | undefined;\n if (options?.handler) {\n const sanitizedRequest = new Request(request.nextUrl.toString(), {\n method: request.method ?? 'GET',\n headers: requestHeaders,\n body: request.body,\n // @ts-expect-error -- NextRequest supports duplex but TS doesn't expose it\n duplex: 'half',\n });\n handlerResponse = await options.handler(\n Object.assign(sanitizedRequest, { nextUrl: request.nextUrl, cookies: request.cookies }) as NextRequest,\n geo\n );\n }\n\n const response = handlerResponse ?? NextResponse.next({\n request: { headers: requestHeaders },\n });\n\n // 8. Set/update the cookie if needed\n if (!cookieValue || cookieGeo.query?.value !== clientIp) {\n response.cookies.set(COOKIE_NAME, serializeCookie(geo), {\n path: COOKIE_OPTIONS.path,\n httpOnly: COOKIE_OPTIONS.httpOnly,\n secure: COOKIE_OPTIONS.secure,\n sameSite: COOKIE_OPTIONS.sameSite,\n maxAge: COOKIE_OPTIONS.maxAge,\n });\n }\n\n return response;\n };\n}\n\n/**\n * Create a geo-redirect handler for use with createProxy.\n */\nexport function withGeoRedirect(\n options: GeoRedirectOptions\n): (request: NextRequest, geo: Geo) => NextResponse | undefined {\n const { defaultLocale, localeMap, excludePaths = [] } = options;\n const validLocales = new Set(Object.values(localeMap));\n validLocales.add(defaultLocale);\n\n return (request: NextRequest, geo: Geo): NextResponse | undefined => {\n const pathname = request.nextUrl.pathname;\n\n // Skip excluded paths\n for (const prefix of excludePaths) {\n if (pathname.startsWith(prefix)) {\n return undefined;\n }\n }\n\n // Extract current locale prefix from path\n const segments = pathname.split('/').filter(Boolean);\n const currentPrefix = segments[0];\n\n // If path already has a valid locale prefix, don't redirect\n if (currentPrefix && validLocales.has(currentPrefix)) {\n return undefined;\n }\n\n // Look up locale for the user's country\n const countryCode = geo.location?.country?.code;\n const locale = (countryCode && localeMap[countryCode]) || defaultLocale;\n\n // If resolved locale is the default and path has no locale prefix, no redirect needed\n if (locale === defaultLocale) {\n return undefined;\n }\n\n // Redirect to locale-prefixed path\n const url = request.nextUrl.clone();\n url.pathname = `/${locale}${pathname}`;\n return NextResponse.redirect(url, 307);\n };\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"proxy.mjs","names":[],"sources":["../src/proxy.ts"],"sourcesContent":["declare const __PKG_NAME__: string;\ndeclare const __PKG_VERSION__: string;\n\nimport type { Geo } from '@netloc8/core';\nimport type { NextRequest } from 'next/server';\nimport { NextResponse } from 'next/server';\nimport {\n getClientIp,\n isPublicIp,\n getGeoFromPlatformHeaders,\n fetchGeo,\n normalizeApiResponse,\n parseCookie,\n serializeCookie,\n reconcileGeo,\n COOKIE_NAME,\n COOKIE_OPTIONS,\n} from '@netloc8/core';\n\ninterface CreateProxyOptions {\n timeout?: number;\n apiKey?: string;\n apiUrl?: string;\n testIp?: string;\n handler?: (\n request: NextRequest,\n geo: Geo\n ) => NextResponse | undefined | Promise<NextResponse | undefined>;\n}\n\ninterface GeoRedirectOptions {\n defaultLocale: string;\n localeMap: Record<string, string>;\n excludePaths?: string[];\n}\n\n// --- Header transport ---\n// These map nested Geo paths to/from x-netloc8-* request headers\n// for the proxy → Server Component transport layer.\n\ninterface HeaderEntry {\n header: string;\n get: (geo: Geo) => string | number | boolean | string[] | undefined;\n set: (geo: Geo, raw: string) => void;\n type: 'string' | 'number' | 'boolean' | 'json';\n}\n\nconst HEADER_ENTRIES: HeaderEntry[] = [\n {\n header: 'x-netloc8-ip',\n get: (g) => g.query?.value,\n set: (g, v) => { if (!g.query) g.query = {}; g.query.value = v; },\n type: 'string',\n },\n {\n header: 'x-netloc8-ip-version',\n get: (g) => g.query?.ipVersion,\n set: (g, v) => { const n = parseFloat(v); if (!Number.isFinite(n)) return; if (!g.query) g.query = {}; g.query.ipVersion = n; },\n type: 'number',\n },\n {\n header: 'x-netloc8-continent-code',\n get: (g) => g.location?.continent?.code,\n set: (g, v) => {\n if (!g.location) g.location = {};\n if (!g.location.continent) g.location.continent = {};\n g.location.continent.code = v;\n },\n type: 'string',\n },\n {\n header: 'x-netloc8-continent-name',\n get: (g) => g.location?.continent?.name,\n set: (g, v) => {\n if (!g.location) g.location = {};\n if (!g.location.continent) g.location.continent = {};\n g.location.continent.name = v;\n },\n type: 'string',\n },\n {\n header: 'x-netloc8-country-code',\n get: (g) => g.location?.country?.code,\n set: (g, v) => {\n if (!g.location) g.location = {};\n if (!g.location.country) g.location.country = {};\n g.location.country.code = v;\n },\n type: 'string',\n },\n {\n header: 'x-netloc8-country-name',\n get: (g) => g.location?.country?.name,\n set: (g, v) => {\n if (!g.location) g.location = {};\n if (!g.location.country) g.location.country = {};\n g.location.country.name = v;\n },\n type: 'string',\n },\n {\n header: 'x-netloc8-country-flag',\n get: (g) => g.location?.country?.flag,\n set: (g, v) => {\n if (!g.location) g.location = {};\n if (!g.location.country) g.location.country = {};\n g.location.country.flag = v;\n },\n type: 'string',\n },\n {\n header: 'x-netloc8-country-unions',\n get: (g) => g.location?.country?.unions,\n set: (g, v) => {\n if (!g.location) g.location = {};\n if (!g.location.country) g.location.country = {};\n try {\n const parsed = JSON.parse(v);\n if (Array.isArray(parsed)) {\n g.location.country.unions = parsed;\n }\n } catch {\n // Skip malformed JSON\n }\n },\n type: 'json',\n },\n {\n header: 'x-netloc8-region-code',\n get: (g) => g.location?.region?.code,\n set: (g, v) => {\n if (!g.location) g.location = {};\n if (!g.location.region) g.location.region = {};\n g.location.region.code = v;\n },\n type: 'string',\n },\n {\n header: 'x-netloc8-region-name',\n get: (g) => g.location?.region?.name,\n set: (g, v) => {\n if (!g.location) g.location = {};\n if (!g.location.region) g.location.region = {};\n g.location.region.name = v;\n },\n type: 'string',\n },\n {\n header: 'x-netloc8-district',\n get: (g) => g.location?.district,\n set: (g, v) => { if (!g.location) g.location = {}; g.location.district = v; },\n type: 'string',\n },\n {\n header: 'x-netloc8-city',\n get: (g) => g.location?.city,\n set: (g, v) => { if (!g.location) g.location = {}; g.location.city = v; },\n type: 'string',\n },\n {\n header: 'x-netloc8-postal-code',\n get: (g) => g.location?.postalCode,\n set: (g, v) => { if (!g.location) g.location = {}; g.location.postalCode = v; },\n type: 'string',\n },\n {\n header: 'x-netloc8-latitude',\n get: (g) => g.location?.coordinates?.latitude,\n set: (g, v) => {\n if (!g.location) g.location = {};\n if (!g.location.coordinates) g.location.coordinates = {};\n const n = parseFloat(v); if (!Number.isFinite(n)) return;\n g.location.coordinates.latitude = n;\n },\n type: 'number',\n },\n {\n header: 'x-netloc8-longitude',\n get: (g) => g.location?.coordinates?.longitude,\n set: (g, v) => {\n if (!g.location) g.location = {};\n if (!g.location.coordinates) g.location.coordinates = {};\n const n = parseFloat(v); if (!Number.isFinite(n)) return;\n g.location.coordinates.longitude = n;\n },\n type: 'number',\n },\n {\n header: 'x-netloc8-accuracy-radius',\n get: (g) => g.location?.coordinates?.accuracyRadius,\n set: (g, v) => {\n if (!g.location) g.location = {};\n if (!g.location.coordinates) g.location.coordinates = {};\n const n = parseFloat(v); if (!Number.isFinite(n)) return;\n g.location.coordinates.accuracyRadius = n;\n },\n type: 'number',\n },\n {\n header: 'x-netloc8-timezone',\n get: (g) => g.location?.timezone,\n set: (g, v) => { if (!g.location) g.location = {}; g.location.timezone = v; },\n type: 'string',\n },\n {\n header: 'x-netloc8-utc-offset',\n get: (g) => g.location?.utcOffset,\n set: (g, v) => { if (!g.location) g.location = {}; g.location.utcOffset = v; },\n type: 'string',\n },\n {\n header: 'x-netloc8-geo-confidence',\n get: (g) => g.location?.geoConfidence,\n set: (g, v) => { const n = parseFloat(v); if (!Number.isFinite(n)) return; if (!g.location) g.location = {}; g.location.geoConfidence = n; },\n type: 'number',\n },\n {\n header: 'x-netloc8-asn',\n get: (g) => g.network?.asn,\n set: (g, v) => { if (!g.network) g.network = {}; g.network.asn = v; },\n type: 'string',\n },\n {\n header: 'x-netloc8-asn-org',\n get: (g) => g.network?.organization,\n set: (g, v) => { if (!g.network) g.network = {}; g.network.organization = v; },\n type: 'string',\n },\n {\n header: 'x-netloc8-asn-domain',\n get: (g) => g.network?.domain,\n set: (g, v) => { if (!g.network) g.network = {}; g.network.domain = v; },\n type: 'string',\n },\n {\n header: 'x-netloc8-precision',\n get: (g) => g.meta?.precision,\n set: (g, v) => { if (!g.meta) g.meta = {}; g.meta.precision = v; },\n type: 'string',\n },\n {\n header: 'x-netloc8-degraded',\n get: (g) => g.meta?.degraded,\n set: (g, v) => { if (!g.meta) g.meta = {}; g.meta.degraded = v === 'true'; },\n type: 'boolean',\n },\n {\n header: 'x-netloc8-timezone-from-client',\n get: (g) => g.location?.timezoneFromClient,\n set: (g, v) => { if (!g.location) g.location = {}; g.location.timezoneFromClient = v === 'true'; },\n type: 'boolean',\n },\n];\n\n/**\n * Set x-netloc8-* request headers from a Geo object.\n */\nfunction setGeoHeaders(requestHeaders: Headers, geo: Geo): void {\n for (const entry of HEADER_ENTRIES) {\n const value = entry.get(geo);\n if (value !== undefined && value !== null) {\n if (entry.type === 'json') {\n requestHeaders.set(entry.header, encodeURIComponent(JSON.stringify(value)));\n } else {\n requestHeaders.set(entry.header, encodeURIComponent(String(value)));\n }\n }\n }\n}\n\n/**\n * Read x-netloc8-* request headers back into a Geo object.\n * Used by server.ts to reconstruct Geo on the server side.\n */\nexport function readGeoHeaders(headers: Headers): Geo {\n const geo: Geo = {};\n\n for (const entry of HEADER_ENTRIES) {\n const raw = headers.get(entry.header);\n if (raw === null) {\n continue;\n }\n\n try {\n const decoded = decodeURIComponent(raw);\n entry.set(geo, decoded);\n } catch {\n // Skip this header if decodeURIComponent throws\n }\n }\n\n return geo;\n}\n\n/**\n * Create a Next.js 16 proxy function that resolves geolocation for every\n * matching request.\n *\n * Returns a standard proxy function that can be exported directly from the\n * user's proxy.ts / proxy.js file, or composed with other proxy logic.\n */\nexport function createProxy(options?: CreateProxyOptions):\n (request: NextRequest) => Promise<NextResponse> {\n\n return async (request: NextRequest): Promise<NextResponse> => {\n const apiKey = options?.apiKey ?? process.env.NETLOC8_API_KEY;\n const apiUrl = options?.apiUrl ?? process.env.NETLOC8_API_URL;\n const timeout = options?.timeout ?? 1500;\n const clientId = typeof __PKG_NAME__ !== 'undefined' && typeof __PKG_VERSION__ !== 'undefined'\n ? `${__PKG_NAME__}/${__PKG_VERSION__}`\n : undefined;\n\n // Security: Remove any incoming spoofed headers\n const requestHeaders = new Headers(request.headers);\n for (const entry of HEADER_ENTRIES) {\n requestHeaders.delete(entry.header);\n }\n\n // 1. Determine client IP\n let clientIp: string | undefined;\n\n if (process.env.NODE_ENV !== 'production') {\n clientIp = options?.testIp ?? process.env.NETLOC8_TEST_IP;\n }\n\n if (!clientIp) {\n clientIp = getClientIp(request.headers);\n }\n\n // 2. Check the cookie cache (fast path)\n const cookieValue = request.cookies.get(COOKIE_NAME)?.value;\n const cookieGeo = parseCookie(cookieValue);\n\n // Cookie fast path: only trust timezone/timezoneFromClient from the\n // client-controlled cookie. Re-resolve other geo fields to prevent\n // spoofing of country/region/city via cookie manipulation.\n const cookieTimezone = (\n cookieGeo.location?.timezoneFromClient === true &&\n cookieGeo.query?.value === clientIp\n ) ? {\n timezone: cookieGeo.location.timezone,\n timezoneFromClient: cookieGeo.location.timezoneFromClient,\n } : undefined;\n\n // 3. Extract platform headers (zero-cost)\n const platformGeo = getGeoFromPlatformHeaders(request.headers);\n\n // 4. Decide whether to call the API\n // With API key: await full enrichment (city, coords, ASN, etc.).\n // Without key: attempt lookup with a short timeout to avoid\n // blocking the page — fall back to platform headers if it\n // doesn't complete in time.\n const ipChanged = cookieGeo.query?.value !== clientIp;\n let apiGeo: Geo | undefined;\n\n // Dev-mode warning: only on new visitors to avoid console spam\n if (process.env.NODE_ENV !== 'production' && !apiKey && ipChanged) {\n if (platformGeo.location?.country?.code) {\n console.warn(\n '[netloc8] No API key configured \\u2014 using platform headers only (country-level).\\n' +\n ' Get a free key at https://netloc8.com for city-level geo.'\n );\n } else {\n console.warn(\n '[netloc8] No API key configured and no platform geo headers detected.\\n' +\n ' A free API key enables faster geo responses. Get one at https://netloc8.com'\n );\n }\n }\n\n if (clientIp && isPublicIp(clientIp) && ipChanged) {\n if (apiKey) {\n const raw = await fetchGeo(clientIp, { apiKey, apiUrl, timeout, clientId });\n if (raw) {\n apiGeo = normalizeApiResponse(raw, clientIp);\n }\n } else {\n // No API key: attempt geo lookup with a short timeout.\n // Falls back to platform headers if the request doesn't complete.\n fetchGeo(clientIp, {\n apiUrl, timeout: 100, clientId, allowAnonymous: true,\n }).catch(() => {});\n }\n }\n\n // 5. Reconcile all sources — cookie is lowest priority in\n // reconcileGeo, so platform headers and API data overwrite it.\n // Pass the full cookie so self-hosted deployments (no platform\n // headers, API call skipped) still have city/country/region.\n const geo = reconcileGeo({\n cookie: cookieGeo.query?.value ? cookieGeo : undefined,\n platform: platformGeo,\n api: apiGeo,\n ip: clientIp,\n });\n\n // Apply trusted cookie timezone if available\n if (cookieTimezone) {\n if (!geo.location) geo.location = {};\n geo.location.timezone = cookieTimezone.timezone;\n geo.location.timezoneFromClient = cookieTimezone.timezoneFromClient;\n }\n\n // 6. Set request headers\n setGeoHeaders(requestHeaders, geo);\n\n // 7. Build the response — use sanitized headers in the handler\n let handlerResponse: NextResponse | undefined;\n if (options?.handler) {\n const sanitizedRequest = new Request(request.nextUrl.toString(), {\n method: request.method ?? 'GET',\n headers: requestHeaders,\n body: request.body,\n // @ts-expect-error -- NextRequest supports duplex but TS doesn't expose it\n duplex: 'half',\n });\n handlerResponse = await options.handler(\n Object.assign(sanitizedRequest, { nextUrl: request.nextUrl, cookies: request.cookies }) as NextRequest,\n geo\n );\n }\n\n const response = handlerResponse ?? NextResponse.next({\n request: { headers: requestHeaders },\n });\n\n // 8. Set/update the cookie if needed\n if (!cookieValue || ipChanged) {\n response.cookies.set(COOKIE_NAME, serializeCookie(geo), {\n path: COOKIE_OPTIONS.path,\n httpOnly: COOKIE_OPTIONS.httpOnly,\n secure: COOKIE_OPTIONS.secure,\n sameSite: COOKIE_OPTIONS.sameSite,\n maxAge: COOKIE_OPTIONS.maxAge,\n });\n }\n\n return response;\n };\n}\n\n/**\n * Create a geo-redirect handler for use with createProxy.\n */\nexport function withGeoRedirect(\n options: GeoRedirectOptions\n): (request: NextRequest, geo: Geo) => NextResponse | undefined {\n const { defaultLocale, localeMap, excludePaths = [] } = options;\n const validLocales = new Set(Object.values(localeMap));\n validLocales.add(defaultLocale);\n\n return (request: NextRequest, geo: Geo): NextResponse | undefined => {\n const pathname = request.nextUrl.pathname;\n\n // Skip excluded paths\n for (const prefix of excludePaths) {\n if (pathname.startsWith(prefix)) {\n return undefined;\n }\n }\n\n // Extract current locale prefix from path\n const segments = pathname.split('/').filter(Boolean);\n const currentPrefix = segments[0];\n\n // If path already has a valid locale prefix, don't redirect\n if (currentPrefix && validLocales.has(currentPrefix)) {\n return undefined;\n }\n\n // Look up locale for the user's country\n const countryCode = geo.location?.country?.code;\n const locale = (countryCode && localeMap[countryCode]) || defaultLocale;\n\n // If resolved locale is the default and path has no locale prefix, no redirect needed\n if (locale === defaultLocale) {\n return undefined;\n }\n\n // Redirect to locale-prefixed path\n const url = request.nextUrl.clone();\n url.pathname = `/${locale}${pathname}`;\n return NextResponse.redirect(url, 307);\n };\n}\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@netloc8/nextjs",
3
- "version": "1.0.1",
3
+ "version": "1.1.0",
4
4
  "description": "Next.js geolocation plugin. Server-side proxy, getGeo() for Server Components, useGeo() hook, GeoGate, and locale-based redirects.",
5
5
  "keywords": [
6
6
  "nextjs",