mirror of
https://github.com/LukeHagar/vercel.git
synced 2025-12-09 21:07:46 +00:00
[@vercel/edge] add header helpers (#8036)
* [@vercel/edge] add header helpers * rename getIp => ipAddress, getGeo => geolocation, as suggested by @kikobeats
This commit is contained in:
82
packages/edge/src/edge-headers.ts
Normal file
82
packages/edge/src/edge-headers.ts
Normal file
@@ -0,0 +1,82 @@
|
|||||||
|
/**
|
||||||
|
* City of the original client IP calculated by Vercel Proxy.
|
||||||
|
*/
|
||||||
|
export const CITY_HEADER_NAME = 'x-vercel-ip-city';
|
||||||
|
/**
|
||||||
|
* Country of the original client IP calculated by Vercel Proxy.
|
||||||
|
*/
|
||||||
|
export const COUNTRY_HEADER_NAME = 'x-vercel-ip-country';
|
||||||
|
/**
|
||||||
|
* Ip from Vercel Proxy. Do not confuse it with the client Ip.
|
||||||
|
*/
|
||||||
|
export const IP_HEADER_NAME = 'x-real-ip';
|
||||||
|
/**
|
||||||
|
* Latitude of the original client IP calculated by Vercel Proxy.
|
||||||
|
*/
|
||||||
|
export const LATITUDE_HEADER_NAME = 'x-vercel-ip-latitude';
|
||||||
|
/**
|
||||||
|
* Longitude of the original client IP calculated by Vercel Proxy.
|
||||||
|
*/
|
||||||
|
export const LONGITUDE_HEADER_NAME = 'x-vercel-ip-longitude';
|
||||||
|
/**
|
||||||
|
* Region of the original client IP calculated by Vercel Proxy.
|
||||||
|
*/
|
||||||
|
export const REGION_HEADER_NAME = 'x-vercel-ip-country-region';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* We define a new type so this function can be reused with
|
||||||
|
* the global `Request`, `node-fetch` and other types.
|
||||||
|
*/
|
||||||
|
interface Request {
|
||||||
|
headers: {
|
||||||
|
get(name: string): string | null;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The location information of a given request
|
||||||
|
*/
|
||||||
|
export interface Geo {
|
||||||
|
/** The city that the request originated from */
|
||||||
|
city?: string;
|
||||||
|
/** The country that the request originated from */
|
||||||
|
country?: string;
|
||||||
|
/** The Vercel Edge Network region that received the request */
|
||||||
|
region?: string;
|
||||||
|
/** The latitude of the client */
|
||||||
|
latitude?: string;
|
||||||
|
/** The longitude of the client */
|
||||||
|
longitude?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getHeader(request: Request, key: string): string | undefined {
|
||||||
|
return request.headers.get(key) ?? undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the IP address of the request from the headers.
|
||||||
|
*
|
||||||
|
* @see {@link IP_HEADER_NAME}
|
||||||
|
*/
|
||||||
|
export function ipAddress(request: Request): string | undefined {
|
||||||
|
return getHeader(request, IP_HEADER_NAME);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the location information from for the incoming request
|
||||||
|
*
|
||||||
|
* @see {@link CITY_HEADER_NAME}
|
||||||
|
* @see {@link COUNTRY_HEADER_NAME}
|
||||||
|
* @see {@link REGION_HEADER_NAME}
|
||||||
|
* @see {@link LATITUDE_HEADER_NAME}
|
||||||
|
* @see {@link LONGITUDE_HEADER_NAME}
|
||||||
|
*/
|
||||||
|
export function geolocation(request: Request): Geo {
|
||||||
|
return {
|
||||||
|
city: getHeader(request, CITY_HEADER_NAME),
|
||||||
|
country: getHeader(request, COUNTRY_HEADER_NAME),
|
||||||
|
region: getHeader(request, REGION_HEADER_NAME),
|
||||||
|
latitude: getHeader(request, LATITUDE_HEADER_NAME),
|
||||||
|
longitude: getHeader(request, LONGITUDE_HEADER_NAME),
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -1,2 +1,5 @@
|
|||||||
export type { ExtraResponseInit } from './middleware-helpers';
|
export type { ExtraResponseInit } from './middleware-helpers';
|
||||||
export { next, rewrite } from './middleware-helpers';
|
export * from './middleware-helpers';
|
||||||
|
|
||||||
|
export type { Geo } from './edge-headers';
|
||||||
|
export * from './edge-headers';
|
||||||
|
|||||||
50
packages/edge/test/edge-headers.test.ts
vendored
Normal file
50
packages/edge/test/edge-headers.test.ts
vendored
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
/**
|
||||||
|
* @jest-environment @edge-runtime/jest-environment
|
||||||
|
*/
|
||||||
|
|
||||||
|
import {
|
||||||
|
CITY_HEADER_NAME,
|
||||||
|
COUNTRY_HEADER_NAME,
|
||||||
|
Geo,
|
||||||
|
geolocation,
|
||||||
|
ipAddress,
|
||||||
|
IP_HEADER_NAME,
|
||||||
|
LATITUDE_HEADER_NAME,
|
||||||
|
LONGITUDE_HEADER_NAME,
|
||||||
|
REGION_HEADER_NAME,
|
||||||
|
} from '../src';
|
||||||
|
|
||||||
|
test('`ipAddress` returns the value from the header', () => {
|
||||||
|
const req = new Request('https://example.vercel.sh', {
|
||||||
|
headers: {
|
||||||
|
[IP_HEADER_NAME]: '127.0.0.1',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
expect(ipAddress(req)).toBe('127.0.0.1');
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('`geolocation`', () => {
|
||||||
|
test('returns an empty object if headers are not found', () => {
|
||||||
|
const req = new Request('https://example.vercel.sh');
|
||||||
|
expect(geolocation(req)).toEqual({});
|
||||||
|
});
|
||||||
|
|
||||||
|
test('reads values from headers', () => {
|
||||||
|
const req = new Request('https://example.vercel.sh', {
|
||||||
|
headers: {
|
||||||
|
[CITY_HEADER_NAME]: 'Tel Aviv',
|
||||||
|
[COUNTRY_HEADER_NAME]: 'Israel',
|
||||||
|
[LATITUDE_HEADER_NAME]: '32.109333',
|
||||||
|
[LONGITUDE_HEADER_NAME]: '34.855499',
|
||||||
|
[REGION_HEADER_NAME]: 'fra1',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
expect(geolocation(req)).toEqual<Geo>({
|
||||||
|
city: 'Tel Aviv',
|
||||||
|
country: 'Israel',
|
||||||
|
latitude: '32.109333',
|
||||||
|
longitude: '34.855499',
|
||||||
|
region: 'fra1',
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
Reference in New Issue
Block a user