@hardlydifficult/http 1.0.4 → 1.0.6

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.
Files changed (2) hide show
  1. package/README.md +115 -41
  2. package/package.json +1 -1
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # @hardlydifficult/http
2
2
 
3
- HTTP utilities for safe request/response handling, including constant-time string comparison, body reading with size limits, and JSON responses with CORS headers.
3
+ HTTP utilities for safe request/response handling: body reading with size limits, constant-time comparison, and JSON responses with CORS.
4
4
 
5
5
  ## Installation
6
6
 
@@ -11,75 +11,149 @@ npm install @hardlydifficult/http
11
11
  ## Quick Start
12
12
 
13
13
  ```typescript
14
- import { readBody, sendJson, safeCompare } from '@hardlydifficult/http';
14
+ import { createServer } from "http";
15
+ import { readBody, sendJson, safeCompare } from "@hardlydifficult/http";
16
+
17
+ const server = createServer(async (req, res) => {
18
+ // Read request body safely
19
+ const body = await readBody(req);
20
+ const token = JSON.parse(body).token;
21
+
22
+ // Compare tokens securely
23
+ const isMatch = safeCompare(token, process.env.SECRET_TOKEN ?? "");
24
+ if (!isMatch) {
25
+ sendJson(res, 401, { error: "Unauthorized" }, "https://example.com");
26
+ return;
27
+ }
28
+
29
+ // Send JSON response with CORS headers
30
+ sendJson(res, 200, { message: "Access granted" }, "https://example.com");
31
+ });
32
+
33
+ server.listen(3000);
34
+ ```
35
+
36
+ ## Core HTTP Utilities
37
+
38
+ ### Reading Request Body
15
39
 
16
- // Safe string comparison
17
- const isMatch = safeCompare('secret', 'secret'); // true
40
+ Safely reads request body with a configurable size limit (default 1 MB) to prevent memory exhaustion.
18
41
 
19
- // Read request body with 1MB limit
20
- const body = await readBody(req); // max 1MB
42
+ ```typescript
43
+ import { readBody, MAX_BODY_BYTES } from '@hardlydifficult/http';
44
+ import { IncomingMessage } from 'http';
21
45
 
22
- // Send JSON response with CORS headers
23
- sendJson(res, { status: 'ok' });
46
+ // Default: 1,048,576 bytes (1 MB)
47
+ const body = await readBody(req as IncomingMessage);
48
+ const text = body.toString();
49
+
50
+ // Explicit limit
51
+ const body2 = await readBody(req as IncomingMessage, 500_000); // 500 KB limit
24
52
  ```
25
53
 
26
- ## HTTP Utilities
54
+ | Parameter | Type | Description |
55
+ |---|---|---|
56
+ | req | `IncomingMessage` | HTTP request stream |
57
+ | maxBytes? | `number` | Maximum body size in bytes (default: `MAX_BODY_BYTES`) |
58
+
59
+ **Throws:** `Error` if body exceeds `maxBytes`.
27
60
 
28
- ### Safe String Comparison
61
+ ### Sending JSON Responses
29
62
 
30
- Performs constant-time comparison of two strings to prevent timing attacks.
63
+ Sends JSON with `Content-Type: application/json` and CORS headers.
31
64
 
32
65
  ```typescript
33
- import { safeCompare } from '@hardlydifficult/http';
66
+ import { sendJson } from '@hardlydifficult/http';
67
+ import { ServerResponse } from 'http';
34
68
 
35
- const result = safeCompare('abc123', 'abc123'); // true
36
- const fail = safeCompare('abc123', 'abc124'); // false
69
+ sendJson(res as ServerResponse, { success: true });
70
+ // Sets headers: Content-Type: application/json, Access-Control-Allow-Origin: *
37
71
  ```
38
72
 
39
- | Parameter | Type | Description |
40
- |-----------|--------|---------------------|
41
- | a | string | First string to compare |
42
- | b | string | Second string to compare |
73
+ | Parameter | Type | Description |
74
+ |---|---|---|
75
+ | res | `ServerResponse` | HTTP response object |
76
+ | data | `any` | Serializable data to send as JSON |
43
77
 
44
- ### Reading Request Body
78
+ ## Response Handling
45
79
 
46
- Reads and returns the request body as a string, enforcing a maximum size limit of 1 MB.
80
+ ### `sendJson`
81
+
82
+ Sends a JSON response with CORS headers.
47
83
 
48
84
  ```typescript
49
- import { readBody, MAX_BODY_BYTES } from '@hardlydifficult/http';
85
+ import { sendJson } from "@hardlydifficult/http";
50
86
 
51
- const body = await readBody(req); // max 1,048,576 bytes (1 MB)
52
- // Throws Error if body exceeds MAX_BODY_BYTES
87
+ sendJson(res, 200, { data: "example" }, "https://example.com");
53
88
  ```
54
89
 
55
- | Parameter | Type | Description |
56
- |-----------|--------------------|--------------------------------|
57
- | req | IncomingMessage | Node.js HTTP request object |
90
+ | Parameter | Type | Description |
91
+ |---|---|---|
92
+ | `res` | `ServerResponse` | Node.js HTTP response |
93
+ | `status` | `number` | HTTP status code |
94
+ | `body` | `unknown` | Serializable data to send |
95
+ | `corsOrigin` | `string` | `Access-Control-Allow-Origin` value |
58
96
 
59
- ### Sending JSON Responses
97
+ Sets headers:
98
+ - `Content-Type: application/json`
99
+ - `Access-Control-Allow-Origin: corsOrigin`
100
+ - `Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS`
101
+ - `Access-Control-Allow-Headers: Content-Type, Authorization`
102
+
103
+ ## Security
60
104
 
61
- Sends a JSON response with appropriate `Content-Type` and `Access-Control-Allow-Origin` headers.
105
+ ### `safeCompare`
106
+
107
+ Constant-time string comparison to prevent timing attacks.
62
108
 
63
109
  ```typescript
64
- import { sendJson } from '@hardlydifficult/http';
110
+ import { safeCompare } from "@hardlydifficult/http";
65
111
 
66
- sendJson(res, { message: 'Hello world' });
67
- // Sends: {"message":"Hello world"} with CORS headers
112
+ const isValid = safeCompare(userInput, secretToken);
68
113
  ```
69
114
 
70
- | Parameter | Type | Description |
71
- |-----------|----------|---------------------------------|
72
- | res | ServerResponse | Node.js HTTP response object |
73
- | data | unknown | Data to serialize as JSON |
115
+ Returns `true` for identical strings (including empty strings) and `false` otherwise, regardless of string length or content differences.
116
+
117
+ Handles:
118
+ - Equal/unequal strings
119
+ - Different-length strings
120
+ - Unicode characters
121
+ - Empty strings
122
+
123
+ All comparisons run in time proportional to the first string's length.
74
124
 
75
- ## Appendix
125
+ ```typescript
126
+ import { safeCompare } from '@hardlydifficult/http';
76
127
 
77
- ### Body Size Limit Behavior
128
+ // True (same content)
129
+ const match1 = safeCompare('abc', 'abc'); // => true
78
130
 
79
- The `readBody` function enforces a strict 1 MB (`MAX_BODY_BYTES = 1024 * 1024`) limit. If the request body exceeds this, it throws an error:
131
+ // False (different content)
132
+ const match2 = safeCompare('abc', 'abd'); // => false
133
+
134
+ // False (different length)
135
+ const match3 = safeCompare('abc', 'abcd'); // => false
136
+
137
+ // Works with unicode
138
+ const match4 = safeCompare('你好', '你好'); // => true
139
+ ```
140
+
141
+ | Parameters | Type | Description |
142
+ |---|---|---|
143
+ | a | `string` | First string |
144
+ | b | `string` | Second string |
145
+
146
+ **Returns:** `boolean` — `true` if strings are identical, `false` otherwise.
147
+
148
+ ## Constants
149
+
150
+ ### `MAX_BODY_BYTES`
151
+
152
+ Default maximum body size in bytes (1,048,576 = 1 MB).
80
153
 
81
154
  ```typescript
82
- if (received > MAX_BODY_BYTES) {
83
- throw new Error(`Body exceeded maximum size of ${MAX_BODY_BYTES} bytes`);
84
- }
155
+ import { MAX_BODY_BYTES } from '@hardlydifficult/http';
156
+
157
+ // MAX_BODY_BYTES === 1024 * 1024
158
+ console.log(MAX_BODY_BYTES); // 1048576
85
159
  ```
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hardlydifficult/http",
3
- "version": "1.0.4",
3
+ "version": "1.0.6",
4
4
  "main": "./dist/index.js",
5
5
  "types": "./dist/index.d.ts",
6
6
  "files": [