@remix-run/fetch-proxy 0.5.0 → 0.6.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.
- package/README.md +9 -9
- package/{src/fetch-proxy.ts → dist/index.d.ts} +1 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/{fetch-proxy.js → index.js} +1 -1
- package/dist/index.js.map +7 -0
- package/dist/lib/fetch-proxy.d.ts.map +1 -1
- package/package.json +11 -16
- package/src/index.ts +1 -0
- package/src/lib/fetch-proxy.ts +33 -33
- package/dist/fetch-proxy.cjs +0 -223
- package/dist/fetch-proxy.cjs.map +0 -7
- package/dist/fetch-proxy.d.ts +0 -2
- package/dist/fetch-proxy.d.ts.map +0 -1
- package/dist/fetch-proxy.js.map +0 -7
package/README.md
CHANGED
|
@@ -24,28 +24,28 @@ npm i @remix-run/fetch-proxy
|
|
|
24
24
|
## Usage
|
|
25
25
|
|
|
26
26
|
```ts
|
|
27
|
-
import { createFetchProxy } from '@remix-run/fetch-proxy'
|
|
27
|
+
import { createFetchProxy } from '@remix-run/fetch-proxy'
|
|
28
28
|
|
|
29
29
|
// Create a proxy that sends all requests through to remix.run
|
|
30
|
-
let proxy = createFetchProxy('https://remix.run')
|
|
30
|
+
let proxy = createFetchProxy('https://remix.run')
|
|
31
31
|
|
|
32
32
|
// This fetch handler is probably running as part of your server somewhere...
|
|
33
33
|
function handleFetch(request: Request): Promise<Response> {
|
|
34
|
-
return proxy(request)
|
|
34
|
+
return proxy(request)
|
|
35
35
|
}
|
|
36
36
|
|
|
37
37
|
// Test it out by manually throwing a Request at it
|
|
38
|
-
let response = await handleFetch(new Request('https://shopify.com'))
|
|
38
|
+
let response = await handleFetch(new Request('https://shopify.com'))
|
|
39
39
|
|
|
40
|
-
let text = await response.text()
|
|
41
|
-
let title = text.match(/<title>([^<]+)<\/title>/)[1]
|
|
42
|
-
assert(title.includes('Remix'))
|
|
40
|
+
let text = await response.text()
|
|
41
|
+
let title = text.match(/<title>([^<]+)<\/title>/)[1]
|
|
42
|
+
assert(title.includes('Remix'))
|
|
43
43
|
```
|
|
44
44
|
|
|
45
45
|
## Related Packages
|
|
46
46
|
|
|
47
|
-
- [`node-fetch-server`](https://github.com/remix-run/remix/tree/
|
|
47
|
+
- [`node-fetch-server`](https://github.com/remix-run/remix/tree/main/packages/node-fetch-server) - Build HTTP servers for Node.js using the web fetch API
|
|
48
48
|
|
|
49
49
|
## License
|
|
50
50
|
|
|
51
|
-
See [LICENSE](https://github.com/remix-run/remix/blob/
|
|
51
|
+
See [LICENSE](https://github.com/remix-run/remix/blob/main/LICENSE)
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,iBAAiB,EAAE,KAAK,UAAU,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAA"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../headers/src/lib/param-values.ts", "../../headers/src/lib/utils.ts", "../../headers/src/lib/set-cookie.ts", "../src/lib/fetch-proxy.ts"],
|
|
4
|
+
"sourcesContent": ["export function parseParams(\n input: string,\n delimiter: ';' | ',' = ';',\n): [string, string | undefined][] {\n // This parser splits on the delimiter and unquotes any quoted values\n // like `filename=\"the\\\\ filename.txt\"`.\n let parser =\n delimiter === ';'\n ? /(?:^|;)\\s*([^=;\\s]+)(\\s*=\\s*(?:\"((?:[^\"\\\\]|\\\\.)*)\"|((?:[^;]|\\\\\\;)+))?)?/g\n : /(?:^|,)\\s*([^=,\\s]+)(\\s*=\\s*(?:\"((?:[^\"\\\\]|\\\\.)*)\"|((?:[^,]|\\\\\\,)+))?)?/g\n\n let params: [string, string | undefined][] = []\n\n let match\n while ((match = parser.exec(input)) !== null) {\n let key = match[1].trim()\n\n let value: string | undefined\n if (match[2]) {\n value = (match[3] || match[4] || '').replace(/\\\\(.)/g, '$1').trim()\n }\n\n params.push([key, value])\n }\n\n return params\n}\n\nexport function quote(value: string): string {\n if (value.includes('\"') || value.includes(';') || value.includes(' ')) {\n return `\"${value.replace(/\"/g, '\\\\\"')}\"`\n }\n return value\n}\n", "export function capitalize(str: string): string {\n return str.charAt(0).toUpperCase() + str.slice(1).toLowerCase()\n}\n\nexport function isIterable<T>(value: any): value is Iterable<T> {\n return value != null && typeof value[Symbol.iterator] === 'function'\n}\n\nexport function isValidDate(date: unknown): boolean {\n return date instanceof Date && !isNaN(date.getTime())\n}\n\nexport function quoteEtag(tag: string): string {\n return tag === '*' ? tag : /^(W\\/)?\".*\"$/.test(tag) ? tag : `\"${tag}\"`\n}\n", "import { type HeaderValue } from './header-value.ts'\nimport { parseParams, quote } from './param-values.ts'\nimport { capitalize, isValidDate } from './utils.ts'\n\ntype SameSiteValue = 'Strict' | 'Lax' | 'None'\n\nexport interface SetCookieInit {\n /**\n * The domain of the cookie. For example, `example.com`.\n *\n * [MDN Reference](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie#domaindomain-value)\n */\n domain?: string\n /**\n * The expiration date of the cookie. If not specified, the cookie is a session cookie.\n *\n * [MDN Reference](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie#expiresdate)\n */\n expires?: Date\n /**\n * Indicates this cookie should not be accessible via JavaScript.\n *\n * [MDN Reference](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie#httponly)\n */\n httpOnly?: true\n /**\n * The maximum age of the cookie in seconds.\n *\n * [MDN Reference](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie#max-age)\n */\n maxAge?: number\n /**\n * The name of the cookie.\n *\n * [MDN Reference](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie#cookie-namecookie-value)\n */\n name?: string\n /**\n * The path of the cookie. For example, `/` or `/admin`.\n *\n * [MDN Reference](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie#pathpath-value)\n */\n path?: string\n /**\n * The `SameSite` attribute of the cookie. This attribute lets servers require that a cookie shouldn't be sent with\n * cross-site requests, which provides some protection against cross-site request forgery attacks.\n *\n * [MDN Reference](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie#samesitesamesite-value)\n */\n sameSite?: SameSiteValue\n /**\n * Indicates the cookie should only be sent over HTTPS.\n *\n * [MDN Reference](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie#secure)\n */\n secure?: true\n /**\n * The value of the cookie.\n *\n * [MDN Reference](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie#cookie-namecookie-value)\n */\n value?: string\n}\n\n/**\n * The value of a `Set-Cookie` HTTP header.\n *\n * [MDN `Set-Cookie` Reference](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie)\n *\n * [HTTP/1.1 Specification](https://datatracker.ietf.org/doc/html/rfc6265#section-4.1)\n */\nexport class SetCookie implements HeaderValue, SetCookieInit {\n domain?: string\n expires?: Date\n httpOnly?: true\n maxAge?: number\n name?: string\n path?: string\n sameSite?: SameSiteValue\n secure?: true\n value?: string\n\n constructor(init?: string | SetCookieInit) {\n if (init) {\n if (typeof init === 'string') {\n let params = parseParams(init)\n if (params.length > 0) {\n this.name = params[0][0]\n this.value = params[0][1]\n\n for (let [key, value] of params.slice(1)) {\n switch (key.toLowerCase()) {\n case 'domain':\n this.domain = value\n break\n case 'expires': {\n if (typeof value === 'string') {\n let date = new Date(value)\n if (isValidDate(date)) {\n this.expires = date\n }\n }\n break\n }\n case 'httponly':\n this.httpOnly = true\n break\n case 'max-age': {\n if (typeof value === 'string') {\n let v = parseInt(value, 10)\n if (!isNaN(v)) this.maxAge = v\n }\n break\n }\n case 'path':\n this.path = value\n break\n case 'samesite':\n if (typeof value === 'string' && /strict|lax|none/i.test(value)) {\n this.sameSite = capitalize(value) as SameSiteValue\n }\n break\n case 'secure':\n this.secure = true\n break\n }\n }\n }\n } else {\n this.domain = init.domain\n this.expires = init.expires\n this.httpOnly = init.httpOnly\n this.maxAge = init.maxAge\n this.name = init.name\n this.path = init.path\n this.sameSite = init.sameSite\n this.secure = init.secure\n this.value = init.value\n }\n }\n }\n\n toString(): string {\n if (!this.name) {\n return ''\n }\n\n let parts = [`${this.name}=${quote(this.value || '')}`]\n\n if (this.domain) {\n parts.push(`Domain=${this.domain}`)\n }\n if (this.path) {\n parts.push(`Path=${this.path}`)\n }\n if (this.expires) {\n parts.push(`Expires=${this.expires.toUTCString()}`)\n }\n if (this.maxAge) {\n parts.push(`Max-Age=${this.maxAge}`)\n }\n if (this.secure) {\n parts.push('Secure')\n }\n if (this.httpOnly) {\n parts.push('HttpOnly')\n }\n if (this.sameSite) {\n parts.push(`SameSite=${this.sameSite}`)\n }\n\n return parts.join('; ')\n }\n}\n", "import { SetCookie } from '@remix-run/headers'\n\nexport interface FetchProxyOptions {\n /**\n * The `fetch` function to use for the actual fetch. Defaults to the global `fetch` function.\n */\n fetch?: typeof globalThis.fetch\n /**\n * Set `false` to prevent the `Domain` attribute of `Set-Cookie` headers from being rewritten. By\n * default the domain will be rewritten to the domain of the incoming request.\n */\n rewriteCookieDomain?: boolean\n /**\n * Set `false` to prevent the `Path` attribute of `Set-Cookie` headers from being rewritten. By\n * default the portion of the pathname that matches the proxy target's pathname will be removed.\n */\n rewriteCookiePath?: boolean\n /**\n * Set `true` to add `X-Forwarded-Proto` and `X-Forwarded-Host` headers to the proxied request.\n * Defaults to `false`.\n */\n xForwardedHeaders?: boolean\n}\n\n/**\n * A [`fetch` function](https://developer.mozilla.org/en-US/docs/Web/API/Window/fetch)\n * that forwards requests to another server.\n */\nexport interface FetchProxy {\n (input: URL | RequestInfo, init?: RequestInit): Promise<Response>\n}\n\n/**\n * Creates a `fetch` function that forwards requests to another server.\n * @param target The URL of the server to proxy requests to\n * @param options Options to customize the behavior of the proxy\n * @returns A fetch function that forwards requests to the target server\n */\nexport function createFetchProxy(target: string | URL, options?: FetchProxyOptions): FetchProxy {\n let localFetch = options?.fetch ?? globalThis.fetch\n let rewriteCookieDomain = options?.rewriteCookieDomain ?? true\n let rewriteCookiePath = options?.rewriteCookiePath ?? true\n let xForwardedHeaders = options?.xForwardedHeaders ?? false\n\n let targetUrl = new URL(target)\n if (targetUrl.pathname.endsWith('/')) {\n targetUrl.pathname = targetUrl.pathname.replace(/\\/+$/, '')\n }\n\n return async (input: URL | RequestInfo, init?: RequestInit) => {\n let request = new Request(input, init)\n let url = new URL(request.url)\n\n let proxyUrl = new URL(url.search, targetUrl)\n if (url.pathname !== '/') {\n proxyUrl.pathname =\n proxyUrl.pathname === '/' ? url.pathname : proxyUrl.pathname + url.pathname\n }\n\n let proxyHeaders = new Headers(request.headers)\n if (xForwardedHeaders) {\n proxyHeaders.append('X-Forwarded-Proto', url.protocol.replace(/:$/, ''))\n proxyHeaders.append('X-Forwarded-Host', url.host)\n }\n\n let proxyInit: RequestInit = {\n method: request.method,\n headers: proxyHeaders,\n cache: request.cache,\n credentials: request.credentials,\n integrity: request.integrity,\n keepalive: request.keepalive,\n mode: request.mode,\n redirect: request.redirect,\n referrer: request.referrer,\n referrerPolicy: request.referrerPolicy,\n signal: request.signal,\n ...init,\n }\n if (request.method !== 'GET' && request.method !== 'HEAD') {\n proxyInit.body = request.body\n\n // init.duplex = 'half' must be set when body is a ReadableStream, and Node follows the spec.\n // However, this property is not defined in the TypeScript types for RequestInit, so we have\n // to cast it here in order to set it without a type error.\n // See https://fetch.spec.whatwg.org/#dom-requestinit-duplex\n ;(proxyInit as { duplex: 'half' }).duplex = 'half'\n }\n\n let response = await localFetch(proxyUrl, proxyInit)\n let responseHeaders = new Headers(response.headers)\n\n if (responseHeaders.has('Set-Cookie')) {\n let setCookie = responseHeaders.getSetCookie()\n\n responseHeaders.delete('Set-Cookie')\n\n for (let cookie of setCookie) {\n let header = new SetCookie(cookie)\n\n if (rewriteCookieDomain && header.domain) {\n header.domain = url.host\n }\n\n if (rewriteCookiePath && header.path) {\n if (header.path.startsWith(targetUrl.pathname + '/')) {\n header.path = header.path.slice(targetUrl.pathname.length)\n } else if (header.path === targetUrl.pathname) {\n header.path = '/'\n }\n }\n\n responseHeaders.append('Set-Cookie', header.toString())\n }\n }\n\n return new Response(response.body, {\n status: response.status,\n statusText: response.statusText,\n headers: responseHeaders,\n })\n }\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fetch-proxy.d.ts","sourceRoot":"","sources":["../../src/lib/fetch-proxy.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,iBAAiB;IAChC;;OAEG;IACH,KAAK,CAAC,EAAE,OAAO,UAAU,CAAC,KAAK,
|
|
1
|
+
{"version":3,"file":"fetch-proxy.d.ts","sourceRoot":"","sources":["../../src/lib/fetch-proxy.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,iBAAiB;IAChC;;OAEG;IACH,KAAK,CAAC,EAAE,OAAO,UAAU,CAAC,KAAK,CAAA;IAC/B;;;OAGG;IACH,mBAAmB,CAAC,EAAE,OAAO,CAAA;IAC7B;;;OAGG;IACH,iBAAiB,CAAC,EAAE,OAAO,CAAA;IAC3B;;;OAGG;IACH,iBAAiB,CAAC,EAAE,OAAO,CAAA;CAC5B;AAED;;;GAGG;AACH,MAAM,WAAW,UAAU;IACzB,CAAC,KAAK,EAAE,GAAG,GAAG,WAAW,EAAE,IAAI,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAA;CAClE;AAED;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,MAAM,GAAG,GAAG,EAAE,OAAO,CAAC,EAAE,iBAAiB,GAAG,UAAU,CAoF9F"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@remix-run/fetch-proxy",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.0",
|
|
4
4
|
"description": "An HTTP proxy for the web Fetch API",
|
|
5
5
|
"author": "Michael Jackson <mjijackson@gmail.com>",
|
|
6
6
|
"license": "MIT",
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
"url": "git+https://github.com/remix-run/remix.git",
|
|
10
10
|
"directory": "packages/fetch-proxy"
|
|
11
11
|
},
|
|
12
|
-
"homepage": "https://github.com/remix-run/remix/tree/
|
|
12
|
+
"homepage": "https://github.com/remix-run/remix/tree/main/packages/fetch-proxy#readme",
|
|
13
13
|
"files": [
|
|
14
14
|
"LICENSE",
|
|
15
15
|
"README.md",
|
|
@@ -18,24 +18,19 @@
|
|
|
18
18
|
"!src/**/*.test.ts"
|
|
19
19
|
],
|
|
20
20
|
"type": "module",
|
|
21
|
-
"types": "dist/fetch-proxy.d.ts",
|
|
22
|
-
"module": "dist/fetch-proxy.js",
|
|
23
|
-
"main": "dist/fetch-proxy.cjs",
|
|
24
21
|
"exports": {
|
|
25
22
|
".": {
|
|
26
|
-
"types": "./dist/
|
|
27
|
-
"
|
|
28
|
-
"require": "./dist/fetch-proxy.cjs",
|
|
29
|
-
"default": "./dist/fetch-proxy.js"
|
|
23
|
+
"types": "./dist/index.d.ts",
|
|
24
|
+
"default": "./dist/index.js"
|
|
30
25
|
},
|
|
31
26
|
"./package.json": "./package.json"
|
|
32
27
|
},
|
|
33
28
|
"dependencies": {
|
|
34
|
-
"@remix-run/headers": "^0.
|
|
29
|
+
"@remix-run/headers": "^0.14.0"
|
|
35
30
|
},
|
|
36
31
|
"devDependencies": {
|
|
37
|
-
"@types/node": "^
|
|
38
|
-
"esbuild": "^0.25.
|
|
32
|
+
"@types/node": "^24.6.0",
|
|
33
|
+
"esbuild": "^0.25.10"
|
|
39
34
|
},
|
|
40
35
|
"keywords": [
|
|
41
36
|
"fetch",
|
|
@@ -43,11 +38,11 @@
|
|
|
43
38
|
"proxy"
|
|
44
39
|
],
|
|
45
40
|
"scripts": {
|
|
41
|
+
"build": "pnpm run clean && pnpm run build:types && pnpm run build:esm",
|
|
42
|
+
"build:esm": "esbuild src/index.ts --bundle --outfile=dist/index.js --format=esm --platform=neutral --sourcemap",
|
|
46
43
|
"build:types": "tsc --project tsconfig.build.json",
|
|
47
|
-
"build:esm": "esbuild src/fetch-proxy.ts --bundle --outfile=dist/fetch-proxy.js --format=esm --platform=neutral --sourcemap",
|
|
48
|
-
"build:cjs": "esbuild src/fetch-proxy.ts --bundle --outfile=dist/fetch-proxy.cjs --format=cjs --platform=neutral --sourcemap",
|
|
49
|
-
"build": "pnpm run clean && pnpm run build:types && pnpm run build:esm && pnpm run build:cjs",
|
|
50
44
|
"clean": "rm -rf dist",
|
|
51
|
-
"test": "node --disable-warning=ExperimentalWarning --test ./src/**/*.test.ts"
|
|
45
|
+
"test": "node --disable-warning=ExperimentalWarning --test './src/**/*.test.ts'",
|
|
46
|
+
"typecheck": "tsc --noEmit"
|
|
52
47
|
}
|
|
53
48
|
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { type FetchProxyOptions, type FetchProxy, createFetchProxy } from './lib/fetch-proxy.ts'
|
package/src/lib/fetch-proxy.ts
CHANGED
|
@@ -1,25 +1,25 @@
|
|
|
1
|
-
import { SetCookie } from '@remix-run/headers'
|
|
1
|
+
import { SetCookie } from '@remix-run/headers'
|
|
2
2
|
|
|
3
3
|
export interface FetchProxyOptions {
|
|
4
4
|
/**
|
|
5
5
|
* The `fetch` function to use for the actual fetch. Defaults to the global `fetch` function.
|
|
6
6
|
*/
|
|
7
|
-
fetch?: typeof globalThis.fetch
|
|
7
|
+
fetch?: typeof globalThis.fetch
|
|
8
8
|
/**
|
|
9
9
|
* Set `false` to prevent the `Domain` attribute of `Set-Cookie` headers from being rewritten. By
|
|
10
10
|
* default the domain will be rewritten to the domain of the incoming request.
|
|
11
11
|
*/
|
|
12
|
-
rewriteCookieDomain?: boolean
|
|
12
|
+
rewriteCookieDomain?: boolean
|
|
13
13
|
/**
|
|
14
14
|
* Set `false` to prevent the `Path` attribute of `Set-Cookie` headers from being rewritten. By
|
|
15
15
|
* default the portion of the pathname that matches the proxy target's pathname will be removed.
|
|
16
16
|
*/
|
|
17
|
-
rewriteCookiePath?: boolean
|
|
17
|
+
rewriteCookiePath?: boolean
|
|
18
18
|
/**
|
|
19
19
|
* Set `true` to add `X-Forwarded-Proto` and `X-Forwarded-Host` headers to the proxied request.
|
|
20
20
|
* Defaults to `false`.
|
|
21
21
|
*/
|
|
22
|
-
xForwardedHeaders?: boolean
|
|
22
|
+
xForwardedHeaders?: boolean
|
|
23
23
|
}
|
|
24
24
|
|
|
25
25
|
/**
|
|
@@ -27,7 +27,7 @@ export interface FetchProxyOptions {
|
|
|
27
27
|
* that forwards requests to another server.
|
|
28
28
|
*/
|
|
29
29
|
export interface FetchProxy {
|
|
30
|
-
(input: URL | RequestInfo, init?: RequestInit): Promise<Response
|
|
30
|
+
(input: URL | RequestInfo, init?: RequestInit): Promise<Response>
|
|
31
31
|
}
|
|
32
32
|
|
|
33
33
|
/**
|
|
@@ -37,30 +37,30 @@ export interface FetchProxy {
|
|
|
37
37
|
* @returns A fetch function that forwards requests to the target server
|
|
38
38
|
*/
|
|
39
39
|
export function createFetchProxy(target: string | URL, options?: FetchProxyOptions): FetchProxy {
|
|
40
|
-
let localFetch = options?.fetch ?? globalThis.fetch
|
|
41
|
-
let rewriteCookieDomain = options?.rewriteCookieDomain ?? true
|
|
42
|
-
let rewriteCookiePath = options?.rewriteCookiePath ?? true
|
|
43
|
-
let xForwardedHeaders = options?.xForwardedHeaders ?? false
|
|
40
|
+
let localFetch = options?.fetch ?? globalThis.fetch
|
|
41
|
+
let rewriteCookieDomain = options?.rewriteCookieDomain ?? true
|
|
42
|
+
let rewriteCookiePath = options?.rewriteCookiePath ?? true
|
|
43
|
+
let xForwardedHeaders = options?.xForwardedHeaders ?? false
|
|
44
44
|
|
|
45
|
-
let targetUrl = new URL(target)
|
|
45
|
+
let targetUrl = new URL(target)
|
|
46
46
|
if (targetUrl.pathname.endsWith('/')) {
|
|
47
|
-
targetUrl.pathname = targetUrl.pathname.replace(/\/+$/, '')
|
|
47
|
+
targetUrl.pathname = targetUrl.pathname.replace(/\/+$/, '')
|
|
48
48
|
}
|
|
49
49
|
|
|
50
50
|
return async (input: URL | RequestInfo, init?: RequestInit) => {
|
|
51
|
-
let request = new Request(input, init)
|
|
52
|
-
let url = new URL(request.url)
|
|
51
|
+
let request = new Request(input, init)
|
|
52
|
+
let url = new URL(request.url)
|
|
53
53
|
|
|
54
|
-
let proxyUrl = new URL(url.search, targetUrl)
|
|
54
|
+
let proxyUrl = new URL(url.search, targetUrl)
|
|
55
55
|
if (url.pathname !== '/') {
|
|
56
56
|
proxyUrl.pathname =
|
|
57
|
-
proxyUrl.pathname === '/' ? url.pathname : proxyUrl.pathname + url.pathname
|
|
57
|
+
proxyUrl.pathname === '/' ? url.pathname : proxyUrl.pathname + url.pathname
|
|
58
58
|
}
|
|
59
59
|
|
|
60
|
-
let proxyHeaders = new Headers(request.headers)
|
|
60
|
+
let proxyHeaders = new Headers(request.headers)
|
|
61
61
|
if (xForwardedHeaders) {
|
|
62
|
-
proxyHeaders.append('X-Forwarded-Proto', url.protocol.replace(/:$/, ''))
|
|
63
|
-
proxyHeaders.append('X-Forwarded-Host', url.host)
|
|
62
|
+
proxyHeaders.append('X-Forwarded-Proto', url.protocol.replace(/:$/, ''))
|
|
63
|
+
proxyHeaders.append('X-Forwarded-Host', url.host)
|
|
64
64
|
}
|
|
65
65
|
|
|
66
66
|
let proxyInit: RequestInit = {
|
|
@@ -76,41 +76,41 @@ export function createFetchProxy(target: string | URL, options?: FetchProxyOptio
|
|
|
76
76
|
referrerPolicy: request.referrerPolicy,
|
|
77
77
|
signal: request.signal,
|
|
78
78
|
...init,
|
|
79
|
-
}
|
|
79
|
+
}
|
|
80
80
|
if (request.method !== 'GET' && request.method !== 'HEAD') {
|
|
81
|
-
proxyInit.body = request.body
|
|
81
|
+
proxyInit.body = request.body
|
|
82
82
|
|
|
83
83
|
// init.duplex = 'half' must be set when body is a ReadableStream, and Node follows the spec.
|
|
84
84
|
// However, this property is not defined in the TypeScript types for RequestInit, so we have
|
|
85
85
|
// to cast it here in order to set it without a type error.
|
|
86
86
|
// See https://fetch.spec.whatwg.org/#dom-requestinit-duplex
|
|
87
|
-
(proxyInit as { duplex: 'half' }).duplex = 'half'
|
|
87
|
+
;(proxyInit as { duplex: 'half' }).duplex = 'half'
|
|
88
88
|
}
|
|
89
89
|
|
|
90
|
-
let response = await localFetch(proxyUrl, proxyInit)
|
|
91
|
-
let responseHeaders = new Headers(response.headers)
|
|
90
|
+
let response = await localFetch(proxyUrl, proxyInit)
|
|
91
|
+
let responseHeaders = new Headers(response.headers)
|
|
92
92
|
|
|
93
93
|
if (responseHeaders.has('Set-Cookie')) {
|
|
94
|
-
let setCookie = responseHeaders.getSetCookie()
|
|
94
|
+
let setCookie = responseHeaders.getSetCookie()
|
|
95
95
|
|
|
96
|
-
responseHeaders.delete('Set-Cookie')
|
|
96
|
+
responseHeaders.delete('Set-Cookie')
|
|
97
97
|
|
|
98
98
|
for (let cookie of setCookie) {
|
|
99
|
-
let header = new SetCookie(cookie)
|
|
99
|
+
let header = new SetCookie(cookie)
|
|
100
100
|
|
|
101
101
|
if (rewriteCookieDomain && header.domain) {
|
|
102
|
-
header.domain = url.host
|
|
102
|
+
header.domain = url.host
|
|
103
103
|
}
|
|
104
104
|
|
|
105
105
|
if (rewriteCookiePath && header.path) {
|
|
106
106
|
if (header.path.startsWith(targetUrl.pathname + '/')) {
|
|
107
|
-
header.path = header.path.slice(targetUrl.pathname.length)
|
|
107
|
+
header.path = header.path.slice(targetUrl.pathname.length)
|
|
108
108
|
} else if (header.path === targetUrl.pathname) {
|
|
109
|
-
header.path = '/'
|
|
109
|
+
header.path = '/'
|
|
110
110
|
}
|
|
111
111
|
}
|
|
112
112
|
|
|
113
|
-
responseHeaders.append('Set-Cookie', header.toString())
|
|
113
|
+
responseHeaders.append('Set-Cookie', header.toString())
|
|
114
114
|
}
|
|
115
115
|
}
|
|
116
116
|
|
|
@@ -118,6 +118,6 @@ export function createFetchProxy(target: string | URL, options?: FetchProxyOptio
|
|
|
118
118
|
status: response.status,
|
|
119
119
|
statusText: response.statusText,
|
|
120
120
|
headers: responseHeaders,
|
|
121
|
-
})
|
|
122
|
-
}
|
|
121
|
+
})
|
|
122
|
+
}
|
|
123
123
|
}
|
package/dist/fetch-proxy.cjs
DELETED
|
@@ -1,223 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __defProp = Object.defineProperty;
|
|
3
|
-
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
-
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
-
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
-
var __export = (target, all) => {
|
|
7
|
-
for (var name in all)
|
|
8
|
-
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
-
};
|
|
10
|
-
var __copyProps = (to, from, except, desc) => {
|
|
11
|
-
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
-
for (let key of __getOwnPropNames(from))
|
|
13
|
-
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
-
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
-
}
|
|
16
|
-
return to;
|
|
17
|
-
};
|
|
18
|
-
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
-
|
|
20
|
-
// src/fetch-proxy.ts
|
|
21
|
-
var fetch_proxy_exports = {};
|
|
22
|
-
__export(fetch_proxy_exports, {
|
|
23
|
-
createFetchProxy: () => createFetchProxy
|
|
24
|
-
});
|
|
25
|
-
module.exports = __toCommonJS(fetch_proxy_exports);
|
|
26
|
-
|
|
27
|
-
// ../headers/src/lib/param-values.ts
|
|
28
|
-
function parseParams(input, delimiter = ";") {
|
|
29
|
-
let parser = delimiter === ";" ? /(?:^|;)\s*([^=;\s]+)(\s*=\s*(?:"((?:[^"\\]|\\.)*)"|((?:[^;]|\\\;)+))?)?/g : /(?:^|,)\s*([^=,\s]+)(\s*=\s*(?:"((?:[^"\\]|\\.)*)"|((?:[^,]|\\\,)+))?)?/g;
|
|
30
|
-
let params = [];
|
|
31
|
-
let match;
|
|
32
|
-
while ((match = parser.exec(input)) !== null) {
|
|
33
|
-
let key = match[1].trim();
|
|
34
|
-
let value;
|
|
35
|
-
if (match[2]) {
|
|
36
|
-
value = (match[3] || match[4] || "").replace(/\\(.)/g, "$1").trim();
|
|
37
|
-
}
|
|
38
|
-
params.push([key, value]);
|
|
39
|
-
}
|
|
40
|
-
return params;
|
|
41
|
-
}
|
|
42
|
-
function quote(value) {
|
|
43
|
-
if (value.includes('"') || value.includes(";") || value.includes(" ")) {
|
|
44
|
-
return `"${value.replace(/"/g, '\\"')}"`;
|
|
45
|
-
}
|
|
46
|
-
return value;
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
// ../headers/src/lib/utils.ts
|
|
50
|
-
function capitalize(str) {
|
|
51
|
-
return str.charAt(0).toUpperCase() + str.slice(1).toLowerCase();
|
|
52
|
-
}
|
|
53
|
-
function isValidDate(date) {
|
|
54
|
-
return date instanceof Date && !isNaN(date.getTime());
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
// ../headers/src/lib/set-cookie.ts
|
|
58
|
-
var SetCookie = class {
|
|
59
|
-
domain;
|
|
60
|
-
expires;
|
|
61
|
-
httpOnly;
|
|
62
|
-
maxAge;
|
|
63
|
-
name;
|
|
64
|
-
path;
|
|
65
|
-
sameSite;
|
|
66
|
-
secure;
|
|
67
|
-
value;
|
|
68
|
-
constructor(init) {
|
|
69
|
-
if (init) {
|
|
70
|
-
if (typeof init === "string") {
|
|
71
|
-
let params = parseParams(init);
|
|
72
|
-
if (params.length > 0) {
|
|
73
|
-
this.name = params[0][0];
|
|
74
|
-
this.value = params[0][1];
|
|
75
|
-
for (let [key, value] of params.slice(1)) {
|
|
76
|
-
switch (key.toLowerCase()) {
|
|
77
|
-
case "domain":
|
|
78
|
-
this.domain = value;
|
|
79
|
-
break;
|
|
80
|
-
case "expires": {
|
|
81
|
-
if (typeof value === "string") {
|
|
82
|
-
let date = new Date(value);
|
|
83
|
-
if (isValidDate(date)) {
|
|
84
|
-
this.expires = date;
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
break;
|
|
88
|
-
}
|
|
89
|
-
case "httponly":
|
|
90
|
-
this.httpOnly = true;
|
|
91
|
-
break;
|
|
92
|
-
case "max-age": {
|
|
93
|
-
if (typeof value === "string") {
|
|
94
|
-
let v = parseInt(value, 10);
|
|
95
|
-
if (!isNaN(v)) this.maxAge = v;
|
|
96
|
-
}
|
|
97
|
-
break;
|
|
98
|
-
}
|
|
99
|
-
case "path":
|
|
100
|
-
this.path = value;
|
|
101
|
-
break;
|
|
102
|
-
case "samesite":
|
|
103
|
-
if (typeof value === "string" && /strict|lax|none/i.test(value)) {
|
|
104
|
-
this.sameSite = capitalize(value);
|
|
105
|
-
}
|
|
106
|
-
break;
|
|
107
|
-
case "secure":
|
|
108
|
-
this.secure = true;
|
|
109
|
-
break;
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
} else {
|
|
114
|
-
this.domain = init.domain;
|
|
115
|
-
this.expires = init.expires;
|
|
116
|
-
this.httpOnly = init.httpOnly;
|
|
117
|
-
this.maxAge = init.maxAge;
|
|
118
|
-
this.name = init.name;
|
|
119
|
-
this.path = init.path;
|
|
120
|
-
this.sameSite = init.sameSite;
|
|
121
|
-
this.secure = init.secure;
|
|
122
|
-
this.value = init.value;
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
toString() {
|
|
127
|
-
if (!this.name) {
|
|
128
|
-
return "";
|
|
129
|
-
}
|
|
130
|
-
let parts = [`${this.name}=${quote(this.value || "")}`];
|
|
131
|
-
if (this.domain) {
|
|
132
|
-
parts.push(`Domain=${this.domain}`);
|
|
133
|
-
}
|
|
134
|
-
if (this.path) {
|
|
135
|
-
parts.push(`Path=${this.path}`);
|
|
136
|
-
}
|
|
137
|
-
if (this.expires) {
|
|
138
|
-
parts.push(`Expires=${this.expires.toUTCString()}`);
|
|
139
|
-
}
|
|
140
|
-
if (this.maxAge) {
|
|
141
|
-
parts.push(`Max-Age=${this.maxAge}`);
|
|
142
|
-
}
|
|
143
|
-
if (this.secure) {
|
|
144
|
-
parts.push("Secure");
|
|
145
|
-
}
|
|
146
|
-
if (this.httpOnly) {
|
|
147
|
-
parts.push("HttpOnly");
|
|
148
|
-
}
|
|
149
|
-
if (this.sameSite) {
|
|
150
|
-
parts.push(`SameSite=${this.sameSite}`);
|
|
151
|
-
}
|
|
152
|
-
return parts.join("; ");
|
|
153
|
-
}
|
|
154
|
-
};
|
|
155
|
-
|
|
156
|
-
// src/lib/fetch-proxy.ts
|
|
157
|
-
function createFetchProxy(target, options) {
|
|
158
|
-
let localFetch = options?.fetch ?? globalThis.fetch;
|
|
159
|
-
let rewriteCookieDomain = options?.rewriteCookieDomain ?? true;
|
|
160
|
-
let rewriteCookiePath = options?.rewriteCookiePath ?? true;
|
|
161
|
-
let xForwardedHeaders = options?.xForwardedHeaders ?? false;
|
|
162
|
-
let targetUrl = new URL(target);
|
|
163
|
-
if (targetUrl.pathname.endsWith("/")) {
|
|
164
|
-
targetUrl.pathname = targetUrl.pathname.replace(/\/+$/, "");
|
|
165
|
-
}
|
|
166
|
-
return async (input, init) => {
|
|
167
|
-
let request = new Request(input, init);
|
|
168
|
-
let url = new URL(request.url);
|
|
169
|
-
let proxyUrl = new URL(url.search, targetUrl);
|
|
170
|
-
if (url.pathname !== "/") {
|
|
171
|
-
proxyUrl.pathname = proxyUrl.pathname === "/" ? url.pathname : proxyUrl.pathname + url.pathname;
|
|
172
|
-
}
|
|
173
|
-
let proxyHeaders = new Headers(request.headers);
|
|
174
|
-
if (xForwardedHeaders) {
|
|
175
|
-
proxyHeaders.append("X-Forwarded-Proto", url.protocol.replace(/:$/, ""));
|
|
176
|
-
proxyHeaders.append("X-Forwarded-Host", url.host);
|
|
177
|
-
}
|
|
178
|
-
let proxyInit = {
|
|
179
|
-
method: request.method,
|
|
180
|
-
headers: proxyHeaders,
|
|
181
|
-
cache: request.cache,
|
|
182
|
-
credentials: request.credentials,
|
|
183
|
-
integrity: request.integrity,
|
|
184
|
-
keepalive: request.keepalive,
|
|
185
|
-
mode: request.mode,
|
|
186
|
-
redirect: request.redirect,
|
|
187
|
-
referrer: request.referrer,
|
|
188
|
-
referrerPolicy: request.referrerPolicy,
|
|
189
|
-
signal: request.signal,
|
|
190
|
-
...init
|
|
191
|
-
};
|
|
192
|
-
if (request.method !== "GET" && request.method !== "HEAD") {
|
|
193
|
-
proxyInit.body = request.body;
|
|
194
|
-
proxyInit.duplex = "half";
|
|
195
|
-
}
|
|
196
|
-
let response = await localFetch(proxyUrl, proxyInit);
|
|
197
|
-
let responseHeaders = new Headers(response.headers);
|
|
198
|
-
if (responseHeaders.has("Set-Cookie")) {
|
|
199
|
-
let setCookie = responseHeaders.getSetCookie();
|
|
200
|
-
responseHeaders.delete("Set-Cookie");
|
|
201
|
-
for (let cookie of setCookie) {
|
|
202
|
-
let header = new SetCookie(cookie);
|
|
203
|
-
if (rewriteCookieDomain && header.domain) {
|
|
204
|
-
header.domain = url.host;
|
|
205
|
-
}
|
|
206
|
-
if (rewriteCookiePath && header.path) {
|
|
207
|
-
if (header.path.startsWith(targetUrl.pathname + "/")) {
|
|
208
|
-
header.path = header.path.slice(targetUrl.pathname.length);
|
|
209
|
-
} else if (header.path === targetUrl.pathname) {
|
|
210
|
-
header.path = "/";
|
|
211
|
-
}
|
|
212
|
-
}
|
|
213
|
-
responseHeaders.append("Set-Cookie", header.toString());
|
|
214
|
-
}
|
|
215
|
-
}
|
|
216
|
-
return new Response(response.body, {
|
|
217
|
-
status: response.status,
|
|
218
|
-
statusText: response.statusText,
|
|
219
|
-
headers: responseHeaders
|
|
220
|
-
});
|
|
221
|
-
};
|
|
222
|
-
}
|
|
223
|
-
//# sourceMappingURL=fetch-proxy.cjs.map
|
package/dist/fetch-proxy.cjs.map
DELETED
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"version": 3,
|
|
3
|
-
"sources": ["../src/fetch-proxy.ts", "../../headers/src/lib/param-values.ts", "../../headers/src/lib/utils.ts", "../../headers/src/lib/set-cookie.ts", "../src/lib/fetch-proxy.ts"],
|
|
4
|
-
"sourcesContent": ["export { type FetchProxyOptions, type FetchProxy, createFetchProxy } from './lib/fetch-proxy.ts';\n", "export function parseParams(\n input: string,\n delimiter: ';' | ',' = ';',\n): [string, string | undefined][] {\n // This parser splits on the delimiter and unquotes any quoted values\n // like `filename=\"the\\\\ filename.txt\"`.\n let parser =\n delimiter === ';'\n ? /(?:^|;)\\s*([^=;\\s]+)(\\s*=\\s*(?:\"((?:[^\"\\\\]|\\\\.)*)\"|((?:[^;]|\\\\\\;)+))?)?/g\n : /(?:^|,)\\s*([^=,\\s]+)(\\s*=\\s*(?:\"((?:[^\"\\\\]|\\\\.)*)\"|((?:[^,]|\\\\\\,)+))?)?/g;\n\n let params: [string, string | undefined][] = [];\n\n let match;\n while ((match = parser.exec(input)) !== null) {\n let key = match[1].trim();\n\n let value: string | undefined;\n if (match[2]) {\n value = (match[3] || match[4] || '').replace(/\\\\(.)/g, '$1').trim();\n }\n\n params.push([key, value]);\n }\n\n return params;\n}\n\nexport function quote(value: string): string {\n if (value.includes('\"') || value.includes(';') || value.includes(' ')) {\n return `\"${value.replace(/\"/g, '\\\\\"')}\"`;\n }\n return value;\n}\n", "export function capitalize(str: string): string {\n return str.charAt(0).toUpperCase() + str.slice(1).toLowerCase();\n}\n\nexport function isIterable<T>(value: any): value is Iterable<T> {\n return value != null && typeof value[Symbol.iterator] === 'function';\n}\n\nexport function isValidDate(date: unknown): boolean {\n return date instanceof Date && !isNaN(date.getTime());\n}\n\nexport function quoteEtag(tag: string): string {\n return tag === '*' ? tag : /^(W\\/)?\".*\"$/.test(tag) ? tag : `\"${tag}\"`;\n}\n", "import { type HeaderValue } from './header-value.ts';\nimport { parseParams, quote } from './param-values.ts';\nimport { capitalize, isValidDate } from './utils.ts';\n\ntype SameSiteValue = 'Strict' | 'Lax' | 'None';\n\nexport interface SetCookieInit {\n /**\n * The domain of the cookie. For example, `example.com`.\n *\n * [MDN Reference](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie#domaindomain-value)\n */\n domain?: string;\n /**\n * The expiration date of the cookie. If not specified, the cookie is a session cookie.\n *\n * [MDN Reference](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie#expiresdate)\n */\n expires?: Date;\n /**\n * Indicates this cookie should not be accessible via JavaScript.\n *\n * [MDN Reference](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie#httponly)\n */\n httpOnly?: true;\n /**\n * The maximum age of the cookie in seconds.\n *\n * [MDN Reference](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie#max-age)\n */\n maxAge?: number;\n /**\n * The name of the cookie.\n *\n * [MDN Reference](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie#cookie-namecookie-value)\n */\n name?: string;\n /**\n * The path of the cookie. For example, `/` or `/admin`.\n *\n * [MDN Reference](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie#pathpath-value)\n */\n path?: string;\n /**\n * The `SameSite` attribute of the cookie. This attribute lets servers require that a cookie shouldn't be sent with\n * cross-site requests, which provides some protection against cross-site request forgery attacks.\n *\n * [MDN Reference](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie#samesitesamesite-value)\n */\n sameSite?: SameSiteValue;\n /**\n * Indicates the cookie should only be sent over HTTPS.\n *\n * [MDN Reference](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie#secure)\n */\n secure?: true;\n /**\n * The value of the cookie.\n *\n * [MDN Reference](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie#cookie-namecookie-value)\n */\n value?: string;\n}\n\n/**\n * The value of a `Set-Cookie` HTTP header.\n *\n * [MDN `Set-Cookie` Reference](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie)\n *\n * [HTTP/1.1 Specification](https://datatracker.ietf.org/doc/html/rfc6265#section-4.1)\n */\nexport class SetCookie implements HeaderValue, SetCookieInit {\n domain?: string;\n expires?: Date;\n httpOnly?: true;\n maxAge?: number;\n name?: string;\n path?: string;\n sameSite?: SameSiteValue;\n secure?: true;\n value?: string;\n\n constructor(init?: string | SetCookieInit) {\n if (init) {\n if (typeof init === 'string') {\n let params = parseParams(init);\n if (params.length > 0) {\n this.name = params[0][0];\n this.value = params[0][1];\n\n for (let [key, value] of params.slice(1)) {\n switch (key.toLowerCase()) {\n case 'domain':\n this.domain = value;\n break;\n case 'expires': {\n if (typeof value === 'string') {\n let date = new Date(value);\n if (isValidDate(date)) {\n this.expires = date;\n }\n }\n break;\n }\n case 'httponly':\n this.httpOnly = true;\n break;\n case 'max-age': {\n if (typeof value === 'string') {\n let v = parseInt(value, 10);\n if (!isNaN(v)) this.maxAge = v;\n }\n break;\n }\n case 'path':\n this.path = value;\n break;\n case 'samesite':\n if (typeof value === 'string' && /strict|lax|none/i.test(value)) {\n this.sameSite = capitalize(value) as SameSiteValue;\n }\n break;\n case 'secure':\n this.secure = true;\n break;\n }\n }\n }\n } else {\n this.domain = init.domain;\n this.expires = init.expires;\n this.httpOnly = init.httpOnly;\n this.maxAge = init.maxAge;\n this.name = init.name;\n this.path = init.path;\n this.sameSite = init.sameSite;\n this.secure = init.secure;\n this.value = init.value;\n }\n }\n }\n\n toString(): string {\n if (!this.name) {\n return '';\n }\n\n let parts = [`${this.name}=${quote(this.value || '')}`];\n\n if (this.domain) {\n parts.push(`Domain=${this.domain}`);\n }\n if (this.path) {\n parts.push(`Path=${this.path}`);\n }\n if (this.expires) {\n parts.push(`Expires=${this.expires.toUTCString()}`);\n }\n if (this.maxAge) {\n parts.push(`Max-Age=${this.maxAge}`);\n }\n if (this.secure) {\n parts.push('Secure');\n }\n if (this.httpOnly) {\n parts.push('HttpOnly');\n }\n if (this.sameSite) {\n parts.push(`SameSite=${this.sameSite}`);\n }\n\n return parts.join('; ');\n }\n}\n", "import { SetCookie } from '@remix-run/headers';\n\nexport interface FetchProxyOptions {\n /**\n * The `fetch` function to use for the actual fetch. Defaults to the global `fetch` function.\n */\n fetch?: typeof globalThis.fetch;\n /**\n * Set `false` to prevent the `Domain` attribute of `Set-Cookie` headers from being rewritten. By\n * default the domain will be rewritten to the domain of the incoming request.\n */\n rewriteCookieDomain?: boolean;\n /**\n * Set `false` to prevent the `Path` attribute of `Set-Cookie` headers from being rewritten. By\n * default the portion of the pathname that matches the proxy target's pathname will be removed.\n */\n rewriteCookiePath?: boolean;\n /**\n * Set `true` to add `X-Forwarded-Proto` and `X-Forwarded-Host` headers to the proxied request.\n * Defaults to `false`.\n */\n xForwardedHeaders?: boolean;\n}\n\n/**\n * A [`fetch` function](https://developer.mozilla.org/en-US/docs/Web/API/Window/fetch)\n * that forwards requests to another server.\n */\nexport interface FetchProxy {\n (input: URL | RequestInfo, init?: RequestInit): Promise<Response>;\n}\n\n/**\n * Creates a `fetch` function that forwards requests to another server.\n * @param target The URL of the server to proxy requests to\n * @param options Options to customize the behavior of the proxy\n * @returns A fetch function that forwards requests to the target server\n */\nexport function createFetchProxy(target: string | URL, options?: FetchProxyOptions): FetchProxy {\n let localFetch = options?.fetch ?? globalThis.fetch;\n let rewriteCookieDomain = options?.rewriteCookieDomain ?? true;\n let rewriteCookiePath = options?.rewriteCookiePath ?? true;\n let xForwardedHeaders = options?.xForwardedHeaders ?? false;\n\n let targetUrl = new URL(target);\n if (targetUrl.pathname.endsWith('/')) {\n targetUrl.pathname = targetUrl.pathname.replace(/\\/+$/, '');\n }\n\n return async (input: URL | RequestInfo, init?: RequestInit) => {\n let request = new Request(input, init);\n let url = new URL(request.url);\n\n let proxyUrl = new URL(url.search, targetUrl);\n if (url.pathname !== '/') {\n proxyUrl.pathname =\n proxyUrl.pathname === '/' ? url.pathname : proxyUrl.pathname + url.pathname;\n }\n\n let proxyHeaders = new Headers(request.headers);\n if (xForwardedHeaders) {\n proxyHeaders.append('X-Forwarded-Proto', url.protocol.replace(/:$/, ''));\n proxyHeaders.append('X-Forwarded-Host', url.host);\n }\n\n let proxyInit: RequestInit = {\n method: request.method,\n headers: proxyHeaders,\n cache: request.cache,\n credentials: request.credentials,\n integrity: request.integrity,\n keepalive: request.keepalive,\n mode: request.mode,\n redirect: request.redirect,\n referrer: request.referrer,\n referrerPolicy: request.referrerPolicy,\n signal: request.signal,\n ...init,\n };\n if (request.method !== 'GET' && request.method !== 'HEAD') {\n proxyInit.body = request.body;\n\n // init.duplex = 'half' must be set when body is a ReadableStream, and Node follows the spec.\n // However, this property is not defined in the TypeScript types for RequestInit, so we have\n // to cast it here in order to set it without a type error.\n // See https://fetch.spec.whatwg.org/#dom-requestinit-duplex\n (proxyInit as { duplex: 'half' }).duplex = 'half';\n }\n\n let response = await localFetch(proxyUrl, proxyInit);\n let responseHeaders = new Headers(response.headers);\n\n if (responseHeaders.has('Set-Cookie')) {\n let setCookie = responseHeaders.getSetCookie();\n\n responseHeaders.delete('Set-Cookie');\n\n for (let cookie of setCookie) {\n let header = new SetCookie(cookie);\n\n if (rewriteCookieDomain && header.domain) {\n header.domain = url.host;\n }\n\n if (rewriteCookiePath && header.path) {\n if (header.path.startsWith(targetUrl.pathname + '/')) {\n header.path = header.path.slice(targetUrl.pathname.length);\n } else if (header.path === targetUrl.pathname) {\n header.path = '/';\n }\n }\n\n responseHeaders.append('Set-Cookie', header.toString());\n }\n }\n\n return new Response(response.body, {\n status: response.status,\n statusText: response.statusText,\n headers: responseHeaders,\n });\n };\n}\n"],
|
|
5
|
-
"mappings": "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",
|
|
6
|
-
"names": []
|
|
7
|
-
}
|
package/dist/fetch-proxy.d.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"fetch-proxy.d.ts","sourceRoot":"","sources":["../src/fetch-proxy.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,iBAAiB,EAAE,KAAK,UAAU,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC"}
|
package/dist/fetch-proxy.js.map
DELETED
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"version": 3,
|
|
3
|
-
"sources": ["../../headers/src/lib/param-values.ts", "../../headers/src/lib/utils.ts", "../../headers/src/lib/set-cookie.ts", "../src/lib/fetch-proxy.ts"],
|
|
4
|
-
"sourcesContent": ["export function parseParams(\n input: string,\n delimiter: ';' | ',' = ';',\n): [string, string | undefined][] {\n // This parser splits on the delimiter and unquotes any quoted values\n // like `filename=\"the\\\\ filename.txt\"`.\n let parser =\n delimiter === ';'\n ? /(?:^|;)\\s*([^=;\\s]+)(\\s*=\\s*(?:\"((?:[^\"\\\\]|\\\\.)*)\"|((?:[^;]|\\\\\\;)+))?)?/g\n : /(?:^|,)\\s*([^=,\\s]+)(\\s*=\\s*(?:\"((?:[^\"\\\\]|\\\\.)*)\"|((?:[^,]|\\\\\\,)+))?)?/g;\n\n let params: [string, string | undefined][] = [];\n\n let match;\n while ((match = parser.exec(input)) !== null) {\n let key = match[1].trim();\n\n let value: string | undefined;\n if (match[2]) {\n value = (match[3] || match[4] || '').replace(/\\\\(.)/g, '$1').trim();\n }\n\n params.push([key, value]);\n }\n\n return params;\n}\n\nexport function quote(value: string): string {\n if (value.includes('\"') || value.includes(';') || value.includes(' ')) {\n return `\"${value.replace(/\"/g, '\\\\\"')}\"`;\n }\n return value;\n}\n", "export function capitalize(str: string): string {\n return str.charAt(0).toUpperCase() + str.slice(1).toLowerCase();\n}\n\nexport function isIterable<T>(value: any): value is Iterable<T> {\n return value != null && typeof value[Symbol.iterator] === 'function';\n}\n\nexport function isValidDate(date: unknown): boolean {\n return date instanceof Date && !isNaN(date.getTime());\n}\n\nexport function quoteEtag(tag: string): string {\n return tag === '*' ? tag : /^(W\\/)?\".*\"$/.test(tag) ? tag : `\"${tag}\"`;\n}\n", "import { type HeaderValue } from './header-value.ts';\nimport { parseParams, quote } from './param-values.ts';\nimport { capitalize, isValidDate } from './utils.ts';\n\ntype SameSiteValue = 'Strict' | 'Lax' | 'None';\n\nexport interface SetCookieInit {\n /**\n * The domain of the cookie. For example, `example.com`.\n *\n * [MDN Reference](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie#domaindomain-value)\n */\n domain?: string;\n /**\n * The expiration date of the cookie. If not specified, the cookie is a session cookie.\n *\n * [MDN Reference](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie#expiresdate)\n */\n expires?: Date;\n /**\n * Indicates this cookie should not be accessible via JavaScript.\n *\n * [MDN Reference](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie#httponly)\n */\n httpOnly?: true;\n /**\n * The maximum age of the cookie in seconds.\n *\n * [MDN Reference](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie#max-age)\n */\n maxAge?: number;\n /**\n * The name of the cookie.\n *\n * [MDN Reference](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie#cookie-namecookie-value)\n */\n name?: string;\n /**\n * The path of the cookie. For example, `/` or `/admin`.\n *\n * [MDN Reference](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie#pathpath-value)\n */\n path?: string;\n /**\n * The `SameSite` attribute of the cookie. This attribute lets servers require that a cookie shouldn't be sent with\n * cross-site requests, which provides some protection against cross-site request forgery attacks.\n *\n * [MDN Reference](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie#samesitesamesite-value)\n */\n sameSite?: SameSiteValue;\n /**\n * Indicates the cookie should only be sent over HTTPS.\n *\n * [MDN Reference](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie#secure)\n */\n secure?: true;\n /**\n * The value of the cookie.\n *\n * [MDN Reference](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie#cookie-namecookie-value)\n */\n value?: string;\n}\n\n/**\n * The value of a `Set-Cookie` HTTP header.\n *\n * [MDN `Set-Cookie` Reference](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie)\n *\n * [HTTP/1.1 Specification](https://datatracker.ietf.org/doc/html/rfc6265#section-4.1)\n */\nexport class SetCookie implements HeaderValue, SetCookieInit {\n domain?: string;\n expires?: Date;\n httpOnly?: true;\n maxAge?: number;\n name?: string;\n path?: string;\n sameSite?: SameSiteValue;\n secure?: true;\n value?: string;\n\n constructor(init?: string | SetCookieInit) {\n if (init) {\n if (typeof init === 'string') {\n let params = parseParams(init);\n if (params.length > 0) {\n this.name = params[0][0];\n this.value = params[0][1];\n\n for (let [key, value] of params.slice(1)) {\n switch (key.toLowerCase()) {\n case 'domain':\n this.domain = value;\n break;\n case 'expires': {\n if (typeof value === 'string') {\n let date = new Date(value);\n if (isValidDate(date)) {\n this.expires = date;\n }\n }\n break;\n }\n case 'httponly':\n this.httpOnly = true;\n break;\n case 'max-age': {\n if (typeof value === 'string') {\n let v = parseInt(value, 10);\n if (!isNaN(v)) this.maxAge = v;\n }\n break;\n }\n case 'path':\n this.path = value;\n break;\n case 'samesite':\n if (typeof value === 'string' && /strict|lax|none/i.test(value)) {\n this.sameSite = capitalize(value) as SameSiteValue;\n }\n break;\n case 'secure':\n this.secure = true;\n break;\n }\n }\n }\n } else {\n this.domain = init.domain;\n this.expires = init.expires;\n this.httpOnly = init.httpOnly;\n this.maxAge = init.maxAge;\n this.name = init.name;\n this.path = init.path;\n this.sameSite = init.sameSite;\n this.secure = init.secure;\n this.value = init.value;\n }\n }\n }\n\n toString(): string {\n if (!this.name) {\n return '';\n }\n\n let parts = [`${this.name}=${quote(this.value || '')}`];\n\n if (this.domain) {\n parts.push(`Domain=${this.domain}`);\n }\n if (this.path) {\n parts.push(`Path=${this.path}`);\n }\n if (this.expires) {\n parts.push(`Expires=${this.expires.toUTCString()}`);\n }\n if (this.maxAge) {\n parts.push(`Max-Age=${this.maxAge}`);\n }\n if (this.secure) {\n parts.push('Secure');\n }\n if (this.httpOnly) {\n parts.push('HttpOnly');\n }\n if (this.sameSite) {\n parts.push(`SameSite=${this.sameSite}`);\n }\n\n return parts.join('; ');\n }\n}\n", "import { SetCookie } from '@remix-run/headers';\n\nexport interface FetchProxyOptions {\n /**\n * The `fetch` function to use for the actual fetch. Defaults to the global `fetch` function.\n */\n fetch?: typeof globalThis.fetch;\n /**\n * Set `false` to prevent the `Domain` attribute of `Set-Cookie` headers from being rewritten. By\n * default the domain will be rewritten to the domain of the incoming request.\n */\n rewriteCookieDomain?: boolean;\n /**\n * Set `false` to prevent the `Path` attribute of `Set-Cookie` headers from being rewritten. By\n * default the portion of the pathname that matches the proxy target's pathname will be removed.\n */\n rewriteCookiePath?: boolean;\n /**\n * Set `true` to add `X-Forwarded-Proto` and `X-Forwarded-Host` headers to the proxied request.\n * Defaults to `false`.\n */\n xForwardedHeaders?: boolean;\n}\n\n/**\n * A [`fetch` function](https://developer.mozilla.org/en-US/docs/Web/API/Window/fetch)\n * that forwards requests to another server.\n */\nexport interface FetchProxy {\n (input: URL | RequestInfo, init?: RequestInit): Promise<Response>;\n}\n\n/**\n * Creates a `fetch` function that forwards requests to another server.\n * @param target The URL of the server to proxy requests to\n * @param options Options to customize the behavior of the proxy\n * @returns A fetch function that forwards requests to the target server\n */\nexport function createFetchProxy(target: string | URL, options?: FetchProxyOptions): FetchProxy {\n let localFetch = options?.fetch ?? globalThis.fetch;\n let rewriteCookieDomain = options?.rewriteCookieDomain ?? true;\n let rewriteCookiePath = options?.rewriteCookiePath ?? true;\n let xForwardedHeaders = options?.xForwardedHeaders ?? false;\n\n let targetUrl = new URL(target);\n if (targetUrl.pathname.endsWith('/')) {\n targetUrl.pathname = targetUrl.pathname.replace(/\\/+$/, '');\n }\n\n return async (input: URL | RequestInfo, init?: RequestInit) => {\n let request = new Request(input, init);\n let url = new URL(request.url);\n\n let proxyUrl = new URL(url.search, targetUrl);\n if (url.pathname !== '/') {\n proxyUrl.pathname =\n proxyUrl.pathname === '/' ? url.pathname : proxyUrl.pathname + url.pathname;\n }\n\n let proxyHeaders = new Headers(request.headers);\n if (xForwardedHeaders) {\n proxyHeaders.append('X-Forwarded-Proto', url.protocol.replace(/:$/, ''));\n proxyHeaders.append('X-Forwarded-Host', url.host);\n }\n\n let proxyInit: RequestInit = {\n method: request.method,\n headers: proxyHeaders,\n cache: request.cache,\n credentials: request.credentials,\n integrity: request.integrity,\n keepalive: request.keepalive,\n mode: request.mode,\n redirect: request.redirect,\n referrer: request.referrer,\n referrerPolicy: request.referrerPolicy,\n signal: request.signal,\n ...init,\n };\n if (request.method !== 'GET' && request.method !== 'HEAD') {\n proxyInit.body = request.body;\n\n // init.duplex = 'half' must be set when body is a ReadableStream, and Node follows the spec.\n // However, this property is not defined in the TypeScript types for RequestInit, so we have\n // to cast it here in order to set it without a type error.\n // See https://fetch.spec.whatwg.org/#dom-requestinit-duplex\n (proxyInit as { duplex: 'half' }).duplex = 'half';\n }\n\n let response = await localFetch(proxyUrl, proxyInit);\n let responseHeaders = new Headers(response.headers);\n\n if (responseHeaders.has('Set-Cookie')) {\n let setCookie = responseHeaders.getSetCookie();\n\n responseHeaders.delete('Set-Cookie');\n\n for (let cookie of setCookie) {\n let header = new SetCookie(cookie);\n\n if (rewriteCookieDomain && header.domain) {\n header.domain = url.host;\n }\n\n if (rewriteCookiePath && header.path) {\n if (header.path.startsWith(targetUrl.pathname + '/')) {\n header.path = header.path.slice(targetUrl.pathname.length);\n } else if (header.path === targetUrl.pathname) {\n header.path = '/';\n }\n }\n\n responseHeaders.append('Set-Cookie', header.toString());\n }\n }\n\n return new Response(response.body, {\n status: response.status,\n statusText: response.statusText,\n headers: responseHeaders,\n });\n };\n}\n"],
|
|
5
|
-
"mappings": "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",
|
|
6
|
-
"names": []
|
|
7
|
-
}
|