diff --git a/.yarn/cache/@fastify-busboy-npm-2.1.1-455d8b6bf5-42c32ef75e.zip b/.yarn/cache/@fastify-busboy-npm-2.1.1-455d8b6bf5-42c32ef75e.zip
new file mode 100644
index 0000000..16026e2
Binary files /dev/null and b/.yarn/cache/@fastify-busboy-npm-2.1.1-455d8b6bf5-42c32ef75e.zip differ
diff --git a/.yarn/cache/undici-npm-6.7.0-72b23a7b9b-bc03abd66d.zip b/.yarn/cache/undici-npm-6.7.0-72b23a7b9b-bc03abd66d.zip
new file mode 100644
index 0000000..7292e1a
Binary files /dev/null and b/.yarn/cache/undici-npm-6.7.0-72b23a7b9b-bc03abd66d.zip differ
diff --git a/CHANGELOG.md b/CHANGELOG.md
index cc66f68..f092e0b 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,7 @@
+## 0.2.0 - Add support for native `fetch` proxying
+
+- feat: Support `globalThis.fetch` proxying, allowing native fetch requests to be cached/stubbed/etc
+
## 0.1.3 - Match paths containing dots, serialize browser config values
- fix: match pathnames with dot('.') literals in them
diff --git a/package.json b/package.json
index ada0402..94a923f 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "jambox",
- "version": "0.1.3",
+ "version": "0.2.0",
"description": "Tool for recording and playing back HTTP requests.",
"bin": {
"jam": "./jam.mjs",
@@ -47,6 +47,7 @@
"svelte-routing": "^1.11.0",
"svelte-table": "^0.6.1",
"tail-file": "^1.4.15",
+ "undici": "6.7.0",
"wait-on": "^6.0.1",
"zen-observable": "^0.9.0"
},
diff --git a/recipes/nextjs-graphql-example/.jambox/default.tape.zip b/recipes/nextjs-graphql-example/.jambox/default.tape.zip
new file mode 100644
index 0000000..279653a
Binary files /dev/null and b/recipes/nextjs-graphql-example/.jambox/default.tape.zip differ
diff --git a/recipes/nextjs-graphql-example/.yarn/cache/@next-swc-darwin-arm64-npm-12.3.4-3c587df0e7-8.zip b/recipes/nextjs-graphql-example/.yarn/cache/@next-swc-darwin-arm64-npm-12.3.4-3c587df0e7-8.zip
new file mode 100644
index 0000000..bee0acb
Binary files /dev/null and b/recipes/nextjs-graphql-example/.yarn/cache/@next-swc-darwin-arm64-npm-12.3.4-3c587df0e7-8.zip differ
diff --git a/recipes/nextjs-graphql-example/.yarn/install-state.gz b/recipes/nextjs-graphql-example/.yarn/install-state.gz
index dcd5263..44dfb92 100644
Binary files a/recipes/nextjs-graphql-example/.yarn/install-state.gz and b/recipes/nextjs-graphql-example/.yarn/install-state.gz differ
diff --git a/recipes/nextjs-graphql-example/pages/_app.js b/recipes/nextjs-graphql-example/pages/_app.js
index 39b86cd..a86fad2 100644
--- a/recipes/nextjs-graphql-example/pages/_app.js
+++ b/recipes/nextjs-graphql-example/pages/_app.js
@@ -1,3 +1,11 @@
export default function App({ Component, pageProps }) {
- return ;
+ return (
+ <>
+
+
+ >
+ );
}
diff --git a/recipes/nextjs-graphql-example/pages/server-render.js b/recipes/nextjs-graphql-example/pages/server-render.js
new file mode 100644
index 0000000..2b369c4
--- /dev/null
+++ b/recipes/nextjs-graphql-example/pages/server-render.js
@@ -0,0 +1,88 @@
+import { useState } from 'react';
+
+const query = `query Pokemon($name: String) {
+ pokemon(name: $name) {
+ name
+ image
+ }
+}`;
+
+export default function ServerRenderPage({data: initialData}) {
+ const [name, setName] = useState('Pikachu');
+ const [data, setData] = useState(initialData);
+ const [loading, setLoading] = useState(false);
+
+ const handleSearch = (e) => {
+ e.preventDefault();
+ setLoading(true);
+ fetch('https://graphql-pokemon2.vercel.app', {
+ method: 'POST',
+ headers: {
+ 'Content-Type': 'application/json',
+ Accept: 'application/json',
+ },
+ body: JSON.stringify({
+ query,
+ variables: {
+ name,
+ },
+ }),
+ })
+ .then((res) => res.json())
+ .then(({ data }) => {
+ setLoading(false);
+ setData(data);
+ });
+ };
+
+ const handleInput = (e) => {
+ e.preventDefault();
+ setName(e.target.value);
+ };
+
+ return (
+ <>
+
+
+
+
+
+ {data ? (
+ <>
+
{data.pokemon.name}
+
+ >
+ ) : loading ? (
+
Loading…
+ ) : (
+
Search for an image
+ )}
+
+ >
+ );
+}
+
+
+export async function getServerSideProps() {
+ const res = await fetch('https://graphql-pokemon2.vercel.app', {
+ method: 'POST',
+ headers: {
+ 'Content-Type': 'application/json',
+ Accept: 'application/json',
+ },
+ body: JSON.stringify({
+ query,
+ variables: {
+ name: 'Pikachu',
+ },
+ }),
+ });
+
+ const { data } = await res.json();
+ console.log(data)
+ return {
+ props: {
+ data,
+ },
+ };
+}
diff --git a/src/__mocks__/cache-dir/16068043c24805b3a5ab193fa4a23b8c.json b/src/__mocks__/cache-dir/16068043c24805b3a5ab193fa4a23b8c.json
index 08048ee..1e29dfe 100644
--- a/src/__mocks__/cache-dir/16068043c24805b3a5ab193fa4a23b8c.json
+++ b/src/__mocks__/cache-dir/16068043c24805b3a5ab193fa4a23b8c.json
@@ -1 +1,130 @@
-{"request":{"id":"ebf337e5-ccdf-46be-b629-4651fefa8ad7","matchedRuleId":"2963a70a-837b-4563-bc96-e9049673f097","protocol":"https","httpVersion":"1.1","method":"POST","url":"https://graphql-pokemon2.vercel.app/","path":"/","remoteIpAddress":"::1","remotePort":50448,"headers":{"host":"graphql-pokemon2.vercel.app","connection":"keep-alive","content-length":"125","sec-ch-ua":"\"Not?A_Brand\";v=\"8\", \"Chromium\";v=\"108\"","accept":"application/json","content-type":"application/json","sec-ch-ua-mobile":"?0","user-agent":"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36","sec-ch-ua-platform":"\"Linux\"","origin":"https://jambox-demo-graphql.vercel.app","sec-fetch-site":"cross-site","sec-fetch-mode":"cors","sec-fetch-dest":"empty","referer":"https://jambox-demo-graphql.vercel.app/","accept-encoding":"gzip, deflate, br","accept-language":"en-US,en;q=0.9"},"rawHeaders":[["Host","graphql-pokemon2.vercel.app"],["Connection","keep-alive"],["Content-Length","125"],["sec-ch-ua","\"Not?A_Brand\";v=\"8\", \"Chromium\";v=\"108\""],["Accept","application/json"],["Content-Type","application/json"],["sec-ch-ua-mobile","?0"],["User-Agent","Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36"],["sec-ch-ua-platform","\"Linux\""],["Origin","https://jambox-demo-graphql.vercel.app"],["Sec-Fetch-Site","cross-site"],["Sec-Fetch-Mode","cors"],["Sec-Fetch-Dest","empty"],["Referer","https://jambox-demo-graphql.vercel.app/"],["Accept-Encoding","gzip, deflate, br"],["Accept-Language","en-US,en;q=0.9"]],"tags":[],"timingEvents":{"startTime":1673212233255,"startTimestamp":2040117.9996999986,"bodyReceivedTimestamp":2040118.9439219981},"body":{"buffer":{"type":"Buffer","data":[123,34,113,117,101,114,121,34,58,34,113,117,101,114,121,32,80,111,107,101,109,111,110,40,36,110,97,109,101,58,32,83,116,114,105,110,103,41,32,123,92,110,32,112,111,107,101,109,111,110,40,110,97,109,101,58,32,36,110,97,109,101,41,32,123,92,110,32,32,32,110,97,109,101,92,110,32,32,32,105,109,97,103,101,92,110,32,125,92,110,125,34,44,34,118,97,114,105,97,98,108,101,115,34,58,123,34,110,97,109,101,34,58,34,83,108,111,119,112,111,107,101,34,125,125]}}},"response":{"id":"ebf337e5-ccdf-46be-b629-4651fefa8ad7","statusCode":200,"timingEvents":{"startTime":1673212233255,"startTimestamp":2040117.9996999986,"bodyReceivedTimestamp":2040118.9439219981,"headersSentTimestamp":2040368.6721789986,"responseSentTimestamp":2040372.3621459976},"tags":[],"statusMessage":"OK","headers":{"access-control-allow-methods":"GET,HEAD,PUT,POST,DELETE","access-control-allow-origin":"https://jambox-demo-graphql.vercel.app","cache-control":"public, max-age=0, must-revalidate","connection":"keep-alive","content-length":"97","content-type":"application/json; charset=utf-8","date":"Sun, 08 Jan 2023 21:10:33 GMT","server":"Vercel","strict-transport-security":"max-age=63072000; includeSubDomains; preload","x-vercel-cache":"MISS","x-vercel-id":"iad1::sfo1::qnkr7-1673212233783-e24fced79c98"},"rawHeaders":[["Access-Control-Allow-Methods","GET,HEAD,PUT,POST,DELETE"],["Access-Control-Allow-Origin","https://jambox-demo-graphql.vercel.app"],["Cache-Control","public, max-age=0, must-revalidate"],["Connection","keep-alive"],["Content-Length","97"],["Content-Type","application/json; charset=utf-8"],["Date","Sun, 08 Jan 2023 21:10:33 GMT"],["Server","Vercel"],["Strict-Transport-Security","max-age=63072000; includeSubDomains; preload"],["X-Vercel-Cache","MISS"],["X-Vercel-Id","iad1::sfo1::qnkr7-1673212233783-e24fced79c98"]],"body":{"buffer":{"type":"Buffer","data":[123,34,100,97,116,97,34,58,123,34,112,111,107,101,109,111,110,34,58,123,34,110,97,109,101,34,58,34,83,108,111,119,112,111,107,101,34,44,34,105,109,97,103,101,34,58,34,104,116,116,112,115,58,47,47,105,109,103,46,112,111,107,101,109,111,110,100,98,46,110,101,116,47,97,114,116,119,111,114,107,47,115,108,111,119,112,111,107,101,46,106,112,103,34,125,125,125]}}}}
\ No newline at end of file
+{
+ "request": {
+ "id": "ebf337e5-ccdf-46be-b629-4651fefa8ad7",
+ "matchedRuleId": "2963a70a-837b-4563-bc96-e9049673f097",
+ "protocol": "https",
+ "httpVersion": "1.1",
+ "method": "POST",
+ "url": "https://graphql-pokemon2.vercel.app/",
+ "path": "/",
+ "remoteIpAddress": "::1",
+ "remotePort": 50448,
+ "headers": {
+ "host": "graphql-pokemon2.vercel.app",
+ "connection": "keep-alive",
+ "content-length": "125",
+ "sec-ch-ua": "\"Not?A_Brand\";v=\"8\", \"Chromium\";v=\"108\"",
+ "accept": "application/json",
+ "content-type": "application/json",
+ "sec-ch-ua-mobile": "?0",
+ "user-agent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36",
+ "sec-ch-ua-platform": "\"Linux\"",
+ "origin": "https://jambox-demo-graphql.vercel.app",
+ "sec-fetch-site": "cross-site",
+ "sec-fetch-mode": "cors",
+ "sec-fetch-dest": "empty",
+ "referer": "https://jambox-demo-graphql.vercel.app/",
+ "accept-encoding": "gzip, deflate, br",
+ "accept-language": "en-US,en;q=0.9"
+ },
+ "rawHeaders": [
+ ["Host", "graphql-pokemon2.vercel.app"],
+ ["Connection", "keep-alive"],
+ ["Content-Length", "125"],
+ ["sec-ch-ua", "\"Not?A_Brand\";v=\"8\", \"Chromium\";v=\"108\""],
+ ["Accept", "application/json"],
+ ["Content-Type", "application/json"],
+ ["sec-ch-ua-mobile", "?0"],
+ [
+ "User-Agent",
+ "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36"
+ ],
+ ["sec-ch-ua-platform", "\"Linux\""],
+ ["Origin", "https://jambox-demo-graphql.vercel.app"],
+ ["Sec-Fetch-Site", "cross-site"],
+ ["Sec-Fetch-Mode", "cors"],
+ ["Sec-Fetch-Dest", "empty"],
+ ["Referer", "https://jambox-demo-graphql.vercel.app/"],
+ ["Accept-Encoding", "gzip, deflate, br"],
+ ["Accept-Language", "en-US,en;q=0.9"]
+ ],
+ "tags": [],
+ "timingEvents": {
+ "startTime": 1673212233255,
+ "startTimestamp": 2040117.9996999986,
+ "bodyReceivedTimestamp": 2040118.9439219981
+ },
+ "body": {
+ "buffer": {
+ "type": "Buffer",
+ "data": [
+ 123, 34, 113, 117, 101, 114, 121, 34, 58, 34, 113, 117, 101, 114, 121,
+ 32, 80, 111, 107, 101, 109, 111, 110, 40, 36, 110, 97, 109, 101, 58,
+ 32, 83, 116, 114, 105, 110, 103, 41, 32, 123, 92, 110, 32, 112, 111,
+ 107, 101, 109, 111, 110, 40, 110, 97, 109, 101, 58, 32, 36, 110, 97,
+ 109, 101, 41, 32, 123, 92, 110, 32, 32, 32, 110, 97, 109, 101, 92,
+ 110, 32, 32, 32, 105, 109, 97, 103, 101, 92, 110, 32, 125, 92, 110,
+ 125, 34, 44, 34, 118, 97, 114, 105, 97, 98, 108, 101, 115, 34, 58,
+ 123, 34, 110, 97, 109, 101, 34, 58, 34, 83, 108, 111, 119, 112, 111,
+ 107, 101, 34, 125, 125
+ ]
+ }
+ }
+ },
+ "response": {
+ "id": "ebf337e5-ccdf-46be-b629-4651fefa8ad7",
+ "statusCode": 200,
+ "timingEvents": {
+ "startTime": 1673212233255,
+ "startTimestamp": 2040117.9996999986,
+ "bodyReceivedTimestamp": 2040118.9439219981,
+ "headersSentTimestamp": 2040368.6721789986,
+ "responseSentTimestamp": 2040372.3621459976
+ },
+ "tags": [],
+ "statusMessage": "OK",
+ "headers": {
+ "access-control-allow-methods": "GET,HEAD,PUT,POST,DELETE",
+ "access-control-allow-origin": "https://jambox-demo-graphql.vercel.app",
+ "cache-control": "public, max-age=0, must-revalidate",
+ "connection": "keep-alive",
+ "content-length": "97",
+ "content-type": "application/json; charset=utf-8",
+ "date": "Sun, 08 Jan 2023 21:10:33 GMT",
+ "server": "Vercel",
+ "strict-transport-security": "max-age=63072000; includeSubDomains; preload",
+ "x-vercel-cache": "MISS",
+ "x-vercel-id": "iad1::sfo1::qnkr7-1673212233783-e24fced79c98"
+ },
+ "rawHeaders": [
+ ["Access-Control-Allow-Methods", "GET,HEAD,PUT,POST,DELETE"],
+ ["Access-Control-Allow-Origin", "https://jambox-demo-graphql.vercel.app"],
+ ["Cache-Control", "public, max-age=0, must-revalidate"],
+ ["Connection", "keep-alive"],
+ ["Content-Length", "97"],
+ ["Content-Type", "application/json; charset=utf-8"],
+ ["Date", "Sun, 08 Jan 2023 21:10:33 GMT"],
+ ["Server", "Vercel"],
+ [
+ "Strict-Transport-Security",
+ "max-age=63072000; includeSubDomains; preload"
+ ],
+ ["X-Vercel-Cache", "MISS"],
+ ["X-Vercel-Id", "iad1::sfo1::qnkr7-1673212233783-e24fced79c98"]
+ ],
+ "body": {
+ "buffer": {
+ "type": "Buffer",
+ "data": [
+ 123, 34, 100, 97, 116, 97, 34, 58, 123, 34, 112, 111, 107, 101, 109,
+ 111, 110, 34, 58, 123, 34, 110, 97, 109, 101, 34, 58, 34, 83, 108,
+ 111, 119, 112, 111, 107, 101, 34, 44, 34, 105, 109, 97, 103, 101, 34,
+ 58, 34, 104, 116, 116, 112, 115, 58, 47, 47, 105, 109, 103, 46, 112,
+ 111, 107, 101, 109, 111, 110, 100, 98, 46, 110, 101, 116, 47, 97, 114,
+ 116, 119, 111, 114, 107, 47, 115, 108, 111, 119, 112, 111, 107, 101,
+ 46, 106, 112, 103, 34, 125, 125, 125
+ ]
+ }
+ }
+ }
+}
diff --git a/src/script-helper.js b/src/script-helper.js
index 6ce95f5..3a2fd4e 100644
--- a/src/script-helper.js
+++ b/src/script-helper.js
@@ -1,2 +1,12 @@
+const undici = require('undici');
const globalAgent = require('global-agent');
+
globalAgent.bootstrap();
+
+// Configure "native" `fetch` (e.g. `globalThis.fetch` in Node.js)
+// to work with the `global-agent` proxy
+// @see: https://github.com/gajus/global-agent/issues/52#issuecomment-1134525621
+const ProxyAgent = undici.ProxyAgent;
+const setGlobalDispatcher = undici.setGlobalDispatcher;
+
+setGlobalDispatcher(new ProxyAgent(process.env.GLOBAL_AGENT_HTTP_PROXY));
diff --git a/yarn.lock b/yarn.lock
index 041b72f..97a5e0b 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -1421,6 +1421,13 @@ __metadata:
languageName: node
linkType: hard
+"@fastify/busboy@npm:^2.0.0":
+ version: 2.1.1
+ resolution: "@fastify/busboy@npm:2.1.1"
+ checksum: 42c32ef75e906c9a4809c1e1930a5ca6d4ddc8d138e1a8c8ba5ea07f997db32210617d23b2e4a85fe376316a41a1a0439fc6ff2dedf5126d96f45a9d80754fb2
+ languageName: node
+ linkType: hard
+
"@floating-ui/core@npm:^1.1.0, @floating-ui/core@npm:^1.3.1":
version: 1.3.1
resolution: "@floating-ui/core@npm:1.3.1"
@@ -6145,6 +6152,7 @@ __metadata:
svelte-watch-resize: ^1.0.3
tail-file: ^1.4.15
typescript: ^5.1.3
+ undici: 6.7.0
wait-on: ^6.0.1
webextension-polyfill: ^0.10.0
webpack: ^5.74.0
@@ -9745,6 +9753,15 @@ __metadata:
languageName: node
linkType: hard
+"undici@npm:6.7.0":
+ version: 6.7.0
+ resolution: "undici@npm:6.7.0"
+ dependencies:
+ "@fastify/busboy": ^2.0.0
+ checksum: bc03abd66d2a5db49e46e80453cf32793933db4a56aea5cd5957614e15762a83ef8a00fc54058c8c5fa9c4f4777060b67f37cc98860f49f95f191075cf076d0b
+ languageName: node
+ linkType: hard
+
"unicode-canonical-property-names-ecmascript@npm:^2.0.0":
version: 2.0.0
resolution: "unicode-canonical-property-names-ecmascript@npm:2.0.0"