@zudojs/serialization 1.2.1 → 1.2.3

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 CHANGED
@@ -143,6 +143,11 @@ Failures throw `@zudojs/errors` serialization classes: `SerializationPayloadTooL
143
143
  or malformed tags under `strict`), `TransformerError` and `SerializeError` (for
144
144
  example an invalid `Date`). All extend `SerializationError`.
145
145
 
146
+ An oversized string passed to `deserialize` is untrusted input, so its
147
+ `SerializationPayloadTooLargeError` is an exposed 413 whose message names only
148
+ the two sizes. Oversized output from `serialize` was built by the server, so
149
+ it is an unexposed 500 that public error responses do not describe.
150
+
146
151
  ### Serialized errors
147
152
 
148
153
  Stack traces are **not** serialized unless you ask, because a serialized error
@@ -63,7 +63,7 @@ export class JSONSerializer {
63
63
  const json = opts.pretty
64
64
  ? JSON.stringify(transformed, null, opts.indent ?? 2)
65
65
  : JSON.stringify(transformed);
66
- assertByteSize(json, maxSize);
66
+ assertByteSize(json, maxSize, "output");
67
67
  return json;
68
68
  }
69
69
  // The fast path stays a bare `JSON.stringify` by default, but a depth
@@ -76,7 +76,7 @@ export class JSONSerializer {
76
76
  const json = opts.pretty
77
77
  ? JSON.stringify(value, null, opts.indent ?? 2)
78
78
  : JSON.stringify(value);
79
- assertByteSize(json, maxSize);
79
+ assertByteSize(json, maxSize, "output");
80
80
  return json;
81
81
  }
82
82
  deserialize(value, options) {
@@ -86,7 +86,7 @@ export class JSONSerializer {
86
86
  // the string handed to `deserialize` arrives from a queue, an RPC peer, or
87
87
  // a request body.
88
88
  const maxSize = opts.maxSize ?? SerializationLimits.MAX_SIZE;
89
- assertByteSize(value, maxSize);
89
+ assertByteSize(value, maxSize, "input");
90
90
  const parsed = this.parse(value);
91
91
  if (opts.preserveTypes === true) {
92
92
  const maxDepth = opts.maxDepth ?? SerializationLimits.MAX_DEPTH;
@@ -3,11 +3,22 @@
3
3
  */
4
4
  /** Byte length of a string, in whichever runtime we are on. */
5
5
  export declare function byteLength(value: string): number;
6
+ /**
7
+ * Error options for an oversized payload the server built itself (the
8
+ * output of `serialize`): an internal error that is never shown to the
9
+ * client. Oversized input to `deserialize` keeps the error's default, an
10
+ * exposed 413.
11
+ */
12
+ export declare const SERVER_BUILT_PAYLOAD_ERROR: Readonly<{
13
+ statusCode: 500;
14
+ expose: false;
15
+ }>;
6
16
  /**
7
17
  * Throws `SerializationPayloadTooLargeError` when a JSON string is larger
8
- * than `maxSize` bytes.
18
+ * than `maxSize` bytes. `origin` says whose payload it is: `"input"`
19
+ * (untrusted, an exposed 413) or `"output"` (server-built, an unexposed 500).
9
20
  */
10
- export declare function assertByteSize(json: string, maxSize: number): void;
21
+ export declare function assertByteSize(json: string, maxSize: number, origin: "input" | "output"): void;
11
22
  /**
12
23
  * Assigns a key onto a freshly built object without invoking a setter.
13
24
  *
@@ -9,14 +9,28 @@ export function byteLength(value) {
9
9
  ? Buffer.byteLength(value, "utf-8")
10
10
  : new TextEncoder().encode(value).byteLength;
11
11
  }
12
+ /**
13
+ * Error options for an oversized payload the server built itself (the
14
+ * output of `serialize`): an internal error that is never shown to the
15
+ * client. Oversized input to `deserialize` keeps the error's default, an
16
+ * exposed 413.
17
+ */
18
+ export const SERVER_BUILT_PAYLOAD_ERROR = Object.freeze({
19
+ statusCode: 500,
20
+ expose: false,
21
+ });
12
22
  /**
13
23
  * Throws `SerializationPayloadTooLargeError` when a JSON string is larger
14
- * than `maxSize` bytes.
24
+ * than `maxSize` bytes. `origin` says whose payload it is: `"input"`
25
+ * (untrusted, an exposed 413) or `"output"` (server-built, an unexposed 500).
15
26
  */
16
- export function assertByteSize(json, maxSize) {
27
+ export function assertByteSize(json, maxSize, origin) {
17
28
  const size = byteLength(json);
18
- if (size > maxSize)
19
- throw new SerializationPayloadTooLargeError(size, maxSize);
29
+ if (size <= maxSize)
30
+ return;
31
+ throw origin === "output"
32
+ ? new SerializationPayloadTooLargeError(size, maxSize, SERVER_BUILT_PAYLOAD_ERROR)
33
+ : new SerializationPayloadTooLargeError(size, maxSize);
20
34
  }
21
35
  /**
22
36
  * Assigns a key onto a freshly built object without invoking a setter.
@@ -5,6 +5,7 @@
5
5
  * plain objects (see `jsonSerializer.escape.ts`).
6
6
  */
7
7
  import { InvalidSerializedDataError, SerializationDepthError, TransformerError, isSerializationError, } from "@zudojs/errors";
8
+ import { UNTRUSTED_DEPTH_ERROR } from "@zudojs/validation";
8
9
  import { SerializationLimits, SerializationTags } from "@zudojs/constants";
9
10
  import { isPlainObject } from "@zudojs/types";
10
11
  import { escapedBody } from "./jsonSerializer.escape.js";
@@ -22,7 +23,10 @@ export function restoreValue(walk, value, depth) {
22
23
  if (value === null || typeof value !== "object")
23
24
  return value;
24
25
  if (depth >= walk.maxDepth) {
25
- throw new SerializationDepthError(depth + 1, walk.maxDepth);
26
+ // The restore walk only runs in `deserialize`, on untrusted input, so a
27
+ // too-deep payload is the client's fault: an exposed 400, not a hidden
28
+ // 500 (the serialize-side walk keeps the server-error default).
29
+ throw new SerializationDepthError(depth + 1, walk.maxDepth, UNTRUSTED_DEPTH_ERROR);
26
30
  }
27
31
  if (Array.isArray(value)) {
28
32
  return value.map((item) => restoreValue(walk, item, depth + 1));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zudojs/serialization",
3
- "version": "1.2.1",
3
+ "version": "1.2.3",
4
4
  "description": "Data translation layer with JSON serializer, type transformers, envelopes, and registry for Zudojs applications.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -19,10 +19,10 @@
19
19
  "LICENSE"
20
20
  ],
21
21
  "dependencies": {
22
- "@zudojs/constants": "1.1.2",
23
- "@zudojs/errors": "1.3.0",
22
+ "@zudojs/constants": "1.1.4",
23
+ "@zudojs/errors": "1.3.2",
24
24
  "@zudojs/types": "1.2.0",
25
- "@zudojs/validation": "1.1.0"
25
+ "@zudojs/validation": "1.1.2"
26
26
  },
27
27
  "devDependencies": {
28
28
  "typescript": "7.0.2",