@solidjs/start 1.3.1 → 1.3.2

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.
@@ -124,6 +124,9 @@ class SerovalChunkReader {
124
124
  // deserialize the data
125
125
  const head = new TextDecoder().decode(this.buffer.subarray(1, 11));
126
126
  const bytes = Number.parseInt(head, 16); // ;0x00000000;
127
+ if (Number.isNaN(bytes)) {
128
+ throw new Error("Malformed server function stream header.");
129
+ }
127
130
  // Check if the buffer has enough bytes to be parsed
128
131
  while (bytes > this.buffer.length - 12) {
129
132
  // If it's not enough, and the reader is done
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,78 @@
1
+ import { describe, expect, it, beforeEach, afterEach } from "vitest";
2
+ import { deserializeJSONStream, deserializeJSStream } from "./serialization";
3
+ const encoder = new TextEncoder();
4
+ function makeChunk(dataStr, declaredBytes) {
5
+ const data = encoder.encode(dataStr);
6
+ const bytes = declaredBytes ?? data.length;
7
+ const baseHex = bytes.toString(16).padStart(8, "0");
8
+ const head = encoder.encode(`;0x${baseHex};`);
9
+ const chunk = new Uint8Array(head.length + data.length);
10
+ chunk.set(head);
11
+ chunk.set(data, head.length);
12
+ return chunk;
13
+ }
14
+ function streamFromChunks(chunks) {
15
+ return new ReadableStream({
16
+ start(controller) {
17
+ for (const c of chunks)
18
+ controller.enqueue(c);
19
+ controller.close();
20
+ },
21
+ });
22
+ }
23
+ function responseWithChunks(chunks) {
24
+ if (chunks === null)
25
+ return new Response(null);
26
+ return new Response(streamFromChunks(chunks));
27
+ }
28
+ const cases = [
29
+ { name: "deserializeJSONStream", call: (r) => deserializeJSONStream(r) },
30
+ { name: "deserializeJSStream", call: (r) => deserializeJSStream("server-fn:0", r) },
31
+ ];
32
+ describe("Serialization negative testing (unhappy paths)", () => {
33
+ // TODO: Serialization drains remaining chunks in the background for performance and
34
+ // its async errors aren't propagated to a designated error boundary.
35
+ // This is a temporary catch-all to avoid unhandled rejections in this test suite until
36
+ // we have a better solution for handling async errors in serialization.
37
+ const _unhandledRejectionHandler = (reason, promise) => {
38
+ // eslint-disable-next-line no-console
39
+ console.error("Unhandled rejection (ignored) in serialization.test:", reason, promise);
40
+ };
41
+ // Install immediately and retain for the duration of this test file.
42
+ beforeEach(() => {
43
+ process.on("unhandledRejection", _unhandledRejectionHandler);
44
+ });
45
+ afterEach(async () => {
46
+ // Wait for any pending microtasks to allow background processes to complete
47
+ await new Promise(resolve => setTimeout(resolve, 0));
48
+ process.off("unhandledRejection", _unhandledRejectionHandler);
49
+ });
50
+ for (const fn of cases) {
51
+ it(`${fn.name} throws on missing body`, async () => {
52
+ await expect(fn.call(responseWithChunks(null))).rejects.toThrow("missing body");
53
+ });
54
+ it(`${fn.name} throws on plain XML response`, async () => {
55
+ const xml = '<?xml version="1.0" encoding="UTF-8"?><Error><Code>AccessDenied</Code><Message>Access Denied</Message></Error>';
56
+ const chunk = encoder.encode(xml);
57
+ const resp = new Response(new ReadableStream({
58
+ start(controller) {
59
+ controller.enqueue(chunk);
60
+ controller.close();
61
+ },
62
+ }));
63
+ await expect(fn.call(resp)).rejects.toThrow();
64
+ });
65
+ it(`${fn.name} throws Malformed server function stream when header larger than provided bytes`, async () => {
66
+ const chunk = makeChunk("bad", 16); // declare more than actual
67
+ await expect(fn.call(responseWithChunks([chunk]))).rejects.toThrow("Malformed server function stream.");
68
+ });
69
+ it(`${fn.name} throws Malformed server function stream when header smaller than provided bytes`, async () => {
70
+ const chunk = makeChunk("bad", 2); // declare less than actual
71
+ await expect(fn.call(responseWithChunks([chunk]))).rejects.toThrow();
72
+ });
73
+ it(`${fn.name} throws on valid header but invalid JSON body`, async () => {
74
+ const chunk = makeChunk("not-a-json");
75
+ await expect(fn.call(responseWithChunks([chunk]))).rejects.toThrow();
76
+ });
77
+ }
78
+ });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@solidjs/start",
3
- "version": "1.3.1",
3
+ "version": "1.3.2",
4
4
  "type": "module",
5
5
  "author": "Ryan Carniato",
6
6
  "license": "MIT",