Skip to content

Commit 7bb8b1c

Browse files
authored
Merge pull request #61 from Nesquiko/main
Handle already read response body
2 parents 1d97c20 + e938371 commit 7bb8b1c

File tree

7 files changed

+128
-5
lines changed

7 files changed

+128
-5
lines changed

packages/plugins/tests/web/__snapshots__/request.test.ts.snap

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ exports[`Request > crossSerializeAsync > scoped > supports Request 1`] = `"($R=>
44

55
exports[`Request > crossSerializeAsync > supports Request 1`] = `"$R[0]=new Request("http://localhost:3000/",$R[1]={body:$R[2]=new Uint8Array([72,101,108,108,111,32,87,111,114,108,100,33]).buffer,cache:"default",credentials:"same-origin",headers:$R[3]=new Headers($R[4]=[$R[5]=["content-type","text/plain;charset=UTF-8"]]),integrity:"",keepalive:!1,method:"POST",mode:"cors",redirect:"follow",referrer:"about:client",referrerPolicy:""})"`;
66

7+
exports[`Request > crossSerializeAsync > supports already read Request 1`] = `"$R[0]=new Request("http://localhost:3000/",$R[1]={body:$R[2]=new Uint8Array([72,101,108,108,111,32,87,111,114,108,100,33]).buffer,cache:"default",credentials:"same-origin",headers:$R[3]=new Headers($R[4]=[$R[5]=["content-type","text/plain;charset=UTF-8"]]),integrity:"",keepalive:!1,method:"POST",mode:"cors",redirect:"follow",referrer:"about:client",referrerPolicy:""})"`;
8+
79
exports[`Request > crossSerializeStream > scoped > supports Request 1`] = `"($R=>$R[0]=new Request("http://localhost:3000/",$R[1]={body:$R[2]=($R[3]=d=>new ReadableStream({start:c=>{d.on({next:v=>{c.enqueue(v)},throw:v=>{c.error(v)},return:()=>{c.close()}})}}))($R[4]=($R[5]=(b,a,s,l,p,f,e,n)=>(b=[],a=!0,s=!1,l=[],p=0,f=(v,m,x)=>{for(x=0;x<p;x++)l[x]&&l[x][m](v)},n=(o,x,z,c)=>{for(x=0,z=b.length;x<z;x++)(c=b[x],(!a&&x===z-1)?o[s?"return":"throw"](c):o.next(c))},e=(o,t)=>(a&&(l[t=p++]=o),n(o),()=>{a&&(l[t]=void 0)}),{__SEROVAL_STREAM__:!0,on:o=>e(o),next:v=>{a&&(b.push(v),f(v,"next"))},throw:v=>{a&&(b.push(v),f(v,"throw"),a=s=!1,l.length=0)},return:v=>{a&&(b.push(v),f(v,"return"),a=!1,s=!0,l.length=0)}}))()),cache:"default",credentials:"same-origin",headers:$R[6]=new Headers($R[7]=[$R[8]=["content-type","text/plain;charset=UTF-8"]]),integrity:"",keepalive:!1,method:"POST",mode:"cors",redirect:"follow",referrer:"about:client",referrerPolicy:""}))($R["example"])"`;
810
911
exports[`Request > crossSerializeStream > scoped > supports Request 2`] = `"($R=>$R[4].next($R[9]=new Uint8Array($R[10]=new Uint8Array([72,101,108,108,111,32,87,111,114,108,100,33]).buffer,0,12)))($R["example"])"`;
@@ -18,6 +20,8 @@ exports[`Request > crossSerializeStream > supports Request 3`] = `"$R[4].return(
1820
1921
exports[`Request > serializeAsync > supports Request 1`] = `"new Request("http://localhost:3000/",{body:new Uint8Array([72,101,108,108,111,32,87,111,114,108,100,33]).buffer,cache:"default",credentials:"same-origin",headers:new Headers([["content-type","text/plain;charset=UTF-8"]]),integrity:"",keepalive:!1,method:"POST",mode:"cors",redirect:"follow",referrer:"about:client",referrerPolicy:""})"`;
2022
23+
exports[`Request > serializeAsync > supports already read Request 1`] = `"new Request("http://localhost:3000/",{body:null,cache:"default",credentials:"same-origin",headers:new Headers([["content-type","text/plain;charset=UTF-8"]]),integrity:"",keepalive:!1,method:"POST",mode:"cors",redirect:"follow",referrer:"about:client",referrerPolicy:""})"`;
24+
2125
exports[`Request > toCrossJSONStream > supports Request 1`] = `"{"t":25,"i":0,"s":{"url":{"t":1,"s":"http://localhost:3000/"},"options":{"t":10,"i":1,"p":{"k":["body","cache","credentials","headers","integrity","keepalive","method","mode","redirect","referrer","referrerPolicy"],"v":[{"t":25,"i":2,"s":{"factory":{"t":25,"i":3,"c":"seroval-plugins/web/ReadableStreamFactory"},"stream":{"t":31,"i":4,"a":[],"f":{"t":26,"i":5,"s":4}}},"c":"seroval/plugins/web/ReadableStream"},{"t":1,"s":"default"},{"t":1,"s":"same-origin"},{"t":25,"i":6,"s":{"t":9,"i":7,"l":1,"a":[{"t":9,"i":8,"l":2,"a":[{"t":1,"s":"content-type"},{"t":1,"s":"text/plain;charset=UTF-8"}],"o":0}],"o":0},"c":"seroval-plugins/web/Headers"},{"t":1,"s":""},{"t":2,"s":3},{"t":1,"s":"POST"},{"t":1,"s":"cors"},{"t":1,"s":"follow"},{"t":1,"s":"about:client"},{"t":1,"s":""}],"s":11},"o":0}},"c":"seroval-plugins/web/Request"}"`;
2226
2327
exports[`Request > toCrossJSONStream > supports Request 2`] = `"{"t":32,"i":4,"f":{"t":15,"i":9,"l":12,"c":"Uint8Array","f":{"t":19,"i":10,"s":[72,101,108,108,111,32,87,111,114,108,100,33]},"b":0}}"`;
@@ -27,3 +31,5 @@ exports[`Request > toCrossJSONStream > supports Request 3`] = `"{"t":34,"i":4,"f
2731
exports[`Request > toJSONAsync > supports Request 1`] = `"{"t":{"t":25,"i":0,"s":{"url":{"t":1,"s":"http://localhost:3000/"},"options":{"t":10,"i":1,"p":{"k":["body","cache","credentials","headers","integrity","keepalive","method","mode","redirect","referrer","referrerPolicy"],"v":[{"t":19,"i":2,"s":[72,101,108,108,111,32,87,111,114,108,100,33]},{"t":1,"s":"default"},{"t":1,"s":"same-origin"},{"t":25,"i":3,"s":{"t":9,"i":4,"l":1,"a":[{"t":9,"i":5,"l":2,"a":[{"t":1,"s":"content-type"},{"t":1,"s":"text/plain;charset=UTF-8"}],"o":0}],"o":0},"c":"seroval-plugins/web/Headers"},{"t":1,"s":""},{"t":2,"s":3},{"t":1,"s":"POST"},{"t":1,"s":"cors"},{"t":1,"s":"follow"},{"t":1,"s":"about:client"},{"t":1,"s":""}],"s":11},"o":0}},"c":"seroval-plugins/web/Request"},"f":31,"m":[]}"`;
2832
2933
exports[`Request > toJSONAsync > supports Request 2`] = `"{"t":25,"i":0,"s":{"url":{"t":1,"s":"http://localhost:3000/"},"options":{"t":10,"i":1,"p":{"k":["body","cache","credentials","headers","integrity","keepalive","method","mode","redirect","referrer","referrerPolicy"],"v":[{"t":19,"i":2,"s":[72,101,108,108,111,32,87,111,114,108,100,33]},{"t":1,"s":"default"},{"t":1,"s":"same-origin"},{"t":25,"i":3,"s":{"t":9,"i":4,"l":1,"a":[{"t":9,"i":5,"l":2,"a":[{"t":1,"s":"content-type"},{"t":1,"s":"text/plain;charset=UTF-8"}],"o":0}],"o":0},"c":"seroval-plugins/web/Headers"},{"t":1,"s":""},{"t":2,"s":3},{"t":1,"s":"POST"},{"t":1,"s":"cors"},{"t":1,"s":"follow"},{"t":1,"s":"about:client"},{"t":1,"s":""}],"s":11},"o":0}},"c":"seroval-plugins/web/Request"}"`;
34+
35+
exports[`Request > toJSONAsync > supports already read Request 1`] = `"{"t":25,"i":0,"s":{"url":{"t":1,"s":"http://localhost:3000/"},"options":{"t":10,"i":1,"p":{"k":["body","cache","credentials","headers","integrity","keepalive","method","mode","redirect","referrer","referrerPolicy"],"v":[{"t":2,"s":0},{"t":1,"s":"default"},{"t":1,"s":"same-origin"},{"t":25,"i":2,"s":{"t":9,"i":3,"l":1,"a":[{"t":9,"i":4,"l":2,"a":[{"t":1,"s":"content-type"},{"t":1,"s":"text/plain;charset=UTF-8"}],"o":0}],"o":0},"c":"seroval-plugins/web/Headers"},{"t":1,"s":""},{"t":2,"s":3},{"t":1,"s":"POST"},{"t":1,"s":"cors"},{"t":1,"s":"follow"},{"t":1,"s":"about:client"},{"t":1,"s":""}],"s":11},"o":0}},"c":"seroval-plugins/web/Request"}"`;

packages/plugins/tests/web/__snapshots__/response.test.ts.snap

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,12 @@ exports[`Response > crossSerializeStream > supports Response 2`] = `"$R[3].next(
1616
1717
exports[`Response > crossSerializeStream > supports Response 3`] = `"$R[3].return(void 0)"`;
1818
19+
exports[`Response > crossSerializeStream > supports already read Response 1`] = `"$R[0]=new Response(null,$R[1]={headers:$R[2]=new Headers($R[3]=[$R[4]=["content-type","text/plain;charset=UTF-8"]]),status:200,statusText:""})"`;
20+
1921
exports[`Response > serializeAsync > supports Response 1`] = `"new Response(new Uint8Array([72,101,108,108,111,32,87,111,114,108,100,33]).buffer,{headers:new Headers([["content-type","text/plain;charset=UTF-8"]]),status:200,statusText:""})"`;
2022
23+
exports[`Response > supports already read Response 1`] = `"{"t":25,"i":0,"s":{"body":{"t":2,"s":0},"options":{"t":10,"i":1,"p":{"k":["headers","status","statusText"],"v":[{"t":25,"i":2,"s":{"t":9,"i":3,"l":1,"a":[{"t":9,"i":4,"l":2,"a":[{"t":1,"s":"content-type"},{"t":1,"s":"text/plain;charset=UTF-8"}],"o":0}],"o":0},"c":"seroval-plugins/web/Headers"},{"t":0,"s":200},{"t":1,"s":""}],"s":3},"o":0}},"c":"seroval-plugins/web/Response"}"`;
24+
2125
exports[`Response > toCrossJSONStream > supports Response 1`] = `"{"t":25,"i":0,"s":{"body":{"t":25,"i":1,"s":{"factory":{"t":25,"i":2,"c":"seroval-plugins/web/ReadableStreamFactory"},"stream":{"t":31,"i":3,"a":[],"f":{"t":26,"i":4,"s":4}}},"c":"seroval/plugins/web/ReadableStream"},"options":{"t":10,"i":5,"p":{"k":["headers","status","statusText"],"v":[{"t":25,"i":6,"s":{"t":9,"i":7,"l":1,"a":[{"t":9,"i":8,"l":2,"a":[{"t":1,"s":"content-type"},{"t":1,"s":"text/plain;charset=UTF-8"}],"o":0}],"o":0},"c":"seroval-plugins/web/Headers"},{"t":0,"s":200},{"t":1,"s":""}],"s":3},"o":0}},"c":"seroval-plugins/web/Response"}"`;
2226
2327
exports[`Response > toCrossJSONStream > supports Response 2`] = `"{"t":32,"i":3,"f":{"t":15,"i":9,"l":12,"c":"Uint8Array","f":{"t":19,"i":10,"s":[72,101,108,108,111,32,87,111,114,108,100,33]},"b":0}}"`;
@@ -27,3 +31,5 @@ exports[`Response > toCrossJSONStream > supports Response 3`] = `"{"t":34,"i":3,
2731
exports[`Response > toJSONAsync > supports Response 1`] = `"{"t":{"t":25,"i":0,"s":{"body":{"t":19,"i":1,"s":[72,101,108,108,111,32,87,111,114,108,100,33]},"options":{"t":10,"i":2,"p":{"k":["headers","status","statusText"],"v":[{"t":25,"i":3,"s":{"t":9,"i":4,"l":1,"a":[{"t":9,"i":5,"l":2,"a":[{"t":1,"s":"content-type"},{"t":1,"s":"text/plain;charset=UTF-8"}],"o":0}],"o":0},"c":"seroval-plugins/web/Headers"},{"t":0,"s":200},{"t":1,"s":""}],"s":3},"o":0}},"c":"seroval-plugins/web/Response"},"f":31,"m":[]}"`;
2832
2933
exports[`Response > toJSONAsync > supports Response 2`] = `"{"t":25,"i":0,"s":{"body":{"t":19,"i":1,"s":[72,101,108,108,111,32,87,111,114,108,100,33]},"options":{"t":10,"i":2,"p":{"k":["headers","status","statusText"],"v":[{"t":25,"i":3,"s":{"t":9,"i":4,"l":1,"a":[{"t":9,"i":5,"l":2,"a":[{"t":1,"s":"content-type"},{"t":1,"s":"text/plain;charset=UTF-8"}],"o":0}],"o":0},"c":"seroval-plugins/web/Headers"},{"t":0,"s":200},{"t":1,"s":""}],"s":3},"o":0}},"c":"seroval-plugins/web/Response"}"`;
34+
35+
exports[`Response > toJSONAsync > supports already read Response 1`] = `"{"t":{"t":25,"i":0,"s":{"body":{"t":2,"s":0},"options":{"t":10,"i":1,"p":{"k":["headers","status","statusText"],"v":[{"t":25,"i":2,"s":{"t":9,"i":3,"l":1,"a":[{"t":9,"i":4,"l":2,"a":[{"t":1,"s":"content-type"},{"t":1,"s":"text/plain;charset=UTF-8"}],"o":0}],"o":0},"c":"seroval-plugins/web/Headers"},{"t":0,"s":200},{"t":1,"s":""}],"s":3},"o":0}},"c":"seroval-plugins/web/Response"},"f":31,"m":[]}"`;

packages/plugins/tests/web/request.test.ts

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,23 @@ describe('Request', () => {
3232
expect(back.url).toBe(example.url);
3333
expect(back.method).toBe(example.method);
3434
});
35+
36+
it('supports already read Request', async () => {
37+
const example = new Request(EXAMPLE_URL, {
38+
method: 'POST',
39+
body: EXAMPLE_BODY,
40+
});
41+
await example.text();
42+
const result = await serializeAsync(example, {
43+
plugins: [RequestPlugin],
44+
});
45+
expect(result).toMatchSnapshot();
46+
const back = deserialize<typeof example>(result);
47+
expect(back).toBeInstanceOf(Request);
48+
expect(back.body).toBe(null);
49+
expect(back.url).toBe(example.url);
50+
expect(back.method).toBe(example.method);
51+
});
3552
});
3653
describe('toJSONAsync', () => {
3754
it('supports Request', async () => {
@@ -63,6 +80,17 @@ describe('Request', () => {
6380
});
6481
expect(result).toMatchSnapshot();
6582
});
83+
84+
it('supports already read Request', async () => {
85+
const example = new Request(EXAMPLE_URL, {
86+
method: 'POST',
87+
body: EXAMPLE_BODY,
88+
});
89+
const result = await crossSerializeAsync(example, {
90+
plugins: [RequestPlugin],
91+
});
92+
expect(result).toMatchSnapshot();
93+
});
6694
describe('scoped', () => {
6795
it('supports Request', async () => {
6896
const example = new Request(EXAMPLE_URL, {
@@ -139,6 +167,26 @@ describe('Request', () => {
139167
expect(back.url).toBe(example.url);
140168
expect(back.method).toBe(example.method);
141169
});
170+
171+
it('supports already read Request', async () => {
172+
const example = new Request(EXAMPLE_URL, {
173+
method: 'POST',
174+
body: EXAMPLE_BODY,
175+
});
176+
await example.text();
177+
const result = await toCrossJSONAsync(example, {
178+
plugins: [RequestPlugin],
179+
});
180+
expect(JSON.stringify(result)).toMatchSnapshot();
181+
const back = fromCrossJSON<typeof example>(result, {
182+
plugins: [RequestPlugin],
183+
refs: new Map(),
184+
});
185+
expect(back).toBeInstanceOf(Request);
186+
expect(back.body).toBe(null);
187+
expect(back.url).toBe(example.url);
188+
expect(back.method).toBe(example.method);
189+
});
142190
});
143191
describe('toCrossJSONStream', () => {
144192
it('supports Request', async () =>

packages/plugins/tests/web/response.test.ts

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,22 @@ describe('Response', () => {
4040
expect(back).toBeInstanceOf(Response);
4141
expect(await back.text()).toBe(await example.text());
4242
});
43+
44+
it('supports already read Response', async () => {
45+
const example = new Response(EXAMPLE_BODY);
46+
await example.text();
47+
const result = await toJSONAsync(example, {
48+
plugins: [ResponsePlugin],
49+
});
50+
expect(JSON.stringify(result)).toMatchSnapshot();
51+
const back = fromJSON<typeof example>(result, {
52+
plugins: [ResponsePlugin],
53+
});
54+
expect(back).toBeInstanceOf(Response);
55+
expect(back.body).toBe(null);
56+
});
4357
});
58+
4459
describe('crossSerializeAsync', () => {
4560
it('supports Response', async () => {
4661
const example = new Response(EXAMPLE_BODY);
@@ -78,6 +93,27 @@ describe('Response', () => {
7893
},
7994
});
8095
}));
96+
97+
it('supports already read Response', async () => {
98+
const example = new Response(EXAMPLE_BODY);
99+
await example.text();
100+
101+
new Promise<void>((resolve, reject) => {
102+
crossSerializeStream(example, {
103+
plugins: [ResponsePlugin],
104+
onSerialize(data) {
105+
expect(data).toMatchSnapshot();
106+
},
107+
onDone() {
108+
resolve();
109+
},
110+
onError(error) {
111+
reject(error);
112+
},
113+
});
114+
});
115+
});
116+
81117
describe('scoped', () => {
82118
it('supports Response', async () =>
83119
new Promise<void>((resolve, reject) => {
@@ -113,6 +149,22 @@ describe('Response', () => {
113149
expect(await back.text()).toBe(await example.text());
114150
});
115151
});
152+
153+
it('supports already read Response', async () => {
154+
const example = new Response(EXAMPLE_BODY);
155+
await example.text();
156+
const result = await toCrossJSONAsync(example, {
157+
plugins: [ResponsePlugin],
158+
});
159+
expect(JSON.stringify(result)).toMatchSnapshot();
160+
const back = fromCrossJSON<typeof example>(result, {
161+
plugins: [ResponsePlugin],
162+
refs: new Map(),
163+
});
164+
expect(back).toBeInstanceOf(Response);
165+
expect(back.body).toBe(null);
166+
});
167+
116168
describe('toCrossJSONStream', () => {
117169
it('supports Response', async () =>
118170
new Promise<void>((resolve, reject) => {

packages/plugins/web/request.ts

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,15 +43,22 @@ const RequestPlugin = /* @__PURE__ */ createPlugin<Request, RequestNode>({
4343
options: await ctx.parse(
4444
createRequestOptions(
4545
value,
46-
value.body ? await value.clone().arrayBuffer() : null,
46+
value.body && !value.bodyUsed
47+
? await value.clone().arrayBuffer()
48+
: null,
4749
),
4850
),
4951
};
5052
},
5153
stream(value, ctx) {
5254
return {
5355
url: ctx.parse(value.url),
54-
options: ctx.parse(createRequestOptions(value, value.clone().body)),
56+
options: ctx.parse(
57+
createRequestOptions(
58+
value,
59+
value.body && !value.bodyUsed ? value.clone().body : null,
60+
),
61+
),
5562
};
5663
},
5764
},

packages/plugins/web/response.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,14 +29,18 @@ const ResponsePlugin = /* @__PURE__ */ createPlugin<Response, ResponseNode>({
2929
async async(value, ctx) {
3030
return {
3131
body: await ctx.parse(
32-
value.body ? await value.clone().arrayBuffer() : null,
32+
value.body && !value.bodyUsed
33+
? await value.clone().arrayBuffer()
34+
: null,
3335
),
3436
options: await ctx.parse(createResponseOptions(value)),
3537
};
3638
},
3739
stream(value, ctx) {
3840
return {
39-
body: ctx.parse(value.clone().body),
41+
body: ctx.parse(
42+
value.body && !value.bodyUsed ? value.clone().body : null,
43+
),
4044
options: ctx.parse(createResponseOptions(value)),
4145
};
4246
},

packages/seroval/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "seroval",
33
"type": "module",
4-
"version": "1.3.2",
4+
"version": "1.3.3",
55
"files": [
66
"dist",
77
"src"

0 commit comments

Comments
 (0)