@littlejay/http 0.0.0-stage → 0.1.1

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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Little Jay contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,3 +1,58 @@
1
- # Temporary Holding Version
1
+ # @littlejay/http
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ ESM bounded JSON transport for browsers and Node with platform-compatible fetch, AbortController, and Web Streams, prepared for public npm distribution. No React, CommonJS entry point, or CSS setup is required. The repository validates Node 26.13.0; other runtimes need consumer verification. Public exports and declarations are listed in [package.json](package.json).
4
+
5
+ OpenCode and Codex: have the consuming project's `AGENTS.md` explicitly request this installed README for transport tasks. See the [shared setup/template](https://github.com/jordan-a-young/little-jay/blob/main/docs/CONSUMER-AGENTS.md); installation alone does not activate agent instructions.
6
+
7
+ ## Imports
8
+
9
+ ```ts
10
+ import { fetchJson, HttpError } from "@littlejay/http";
11
+
12
+ const status = await fetchJson("https://example.test/api/health", {
13
+ timeoutMs: 10_000,
14
+ maxResponseBytes: 4096,
15
+ decode(value) {
16
+ if (
17
+ typeof value !== "object" ||
18
+ value === null ||
19
+ !("status" in value) ||
20
+ value.status !== "ok"
21
+ ) {
22
+ throw new Error("Unexpected health payload");
23
+ }
24
+ return value.status;
25
+ },
26
+ });
27
+ ```
28
+
29
+ Use an application URL, not the illustrative host. Node requires absolute URLs; browser-relative URLs use native fetch semantics. `decode` is required and receives `unknown`; TypeScript types do not validate JSON at runtime. Optional `fetch` injects a platform-compatible implementation, `signal` cancels work, and `request` forwards RequestInit options except its signal.
30
+
31
+ ## Transport boundaries
32
+
33
+ The default whole-operation timeout is 10,000 ms; `timeoutMs` must be an integer from 1 through 2,147,483,647. The default response limit is 1,048,576 bytes; `maxResponseBytes` must be a positive safe integer. Invalid limits throw TypeError before I/O. The byte bound applies to actual fetch stream bytes on success **and error**, not just Content-Length; one delivered chunk can exceed the bound before rejection. Error bodies are discarded, not reflected.
34
+
35
+ Success requires UTF-8 JSON (`application/json` or `application/*+json`). Empty/204 bodies, invalid UTF-8/JSON, and decoder failures are errors. Cancellation/deadlines cover fetching, reading, and awaiting an async decoder, but cannot interrupt synchronous JS or stop an already-running decoder. Keep decoders bounded, side-effect-free, and responsible for their own resources.
36
+
37
+ The charset may be absent or quoted/unquoted `UTF-8`. Quoted extension parameters respect backslash escapes and may contain semicolons or charset-like text: `application/json; profile="https://example.test/schema;charset=utf-16"` is accepted. An actual unsupported charset parameter, including one after a quoted extension, or an unterminated quoted value produces `content_type`.
38
+
39
+ `HttpError.code` is `aborted`, `timeout`, `network`, `status`, `size`, `content_type`, `json`, or `decode`; `status` is available for response-related failures. Messages are fixed and omit URL, headers, bodies, abort reasons, and decoder diagnostics. A size failure takes precedence over an unsuccessful HTTP status when its body exceeds the limit. Do not expect an original cause or raw server message.
40
+
41
+ ## Application policy
42
+
43
+ Applications own method/body/headers, credentials, authentication/CSRF, redirect and cache policy, domain validation, retries, and query caches. This transport does not retry writes or install a cache. Defaults of the selected fetch implementation apply when request options are omitted. Use application cancellation signals and map safe error codes to accessible user-facing copy; never expose raw diagnostics or secrets. This package renders no UI and supplies no live announcements or theme.
44
+
45
+ ## Optimization guidance
46
+
47
+ - Set response-byte and timeout budgets for the endpoint instead of increasing limits to hide slow/oversized responses. `fetchJson` buffers and parses a complete bounded JSON value; it is not an incremental JSON, download, or event-stream API. Use pagination or a suitable streaming API for large/unbounded data, without removing validation or bounds.
48
+ - Pass the caller's `signal`, including a query library's supplied signal, so abandoned work can stop. Keep decoding bounded and side-effect-free; a timeout cannot interrupt synchronous parsing/validation or forcibly stop an already-running decoder.
49
+ - Reuse the application's existing request cache/lifecycle layer, such as TanStack Query when already present. Choose query keys, stale windows, deduplication, invalidation and read retries there; do not add a second cache or a retry loop around mutations. Reuse the platform fetch implementation rather than adding a client just to call this helper.
50
+ - Measure request count, transferred/decoded bytes, end-to-end latency and decoding cost for a representative flow before and after changes. Do not log private URLs, headers, payloads or decoder diagnostics as benchmark evidence. Test cancellation and failure paths as well as success.
51
+
52
+ ## Verification
53
+
54
+ Use the application's tests with injected fetch/streams to check decoding, limits, cancellation, safe errors, and any retry/cache policy. Validate required Web APIs in the deployment runtime. The detailed maintainer contract is `docs/HTTP.md` in the source repository, not a file shipped with this package.
55
+
56
+ ## License
57
+
58
+ Project-authored code and documentation are covered by [MIT](LICENSE). Preserve applicable third-party notices.
@@ -0,0 +1,29 @@
1
+ declare const messages: {
2
+ readonly aborted: "Request canceled";
3
+ readonly timeout: "Request timed out";
4
+ readonly network: "Network request failed";
5
+ readonly status: "HTTP request failed";
6
+ readonly size: "Response exceeds the byte limit";
7
+ readonly content_type: "Expected a UTF-8 JSON response";
8
+ readonly json: "Invalid JSON response";
9
+ readonly decode: "Response did not match the expected schema";
10
+ };
11
+ export type HttpErrorCode = keyof typeof messages;
12
+ /** Safe diagnostics only: no URL, response body, headers, abort reason, or original cause. */
13
+ export declare class HttpError extends Error {
14
+ readonly code: HttpErrorCode;
15
+ readonly status?: number;
16
+ constructor(code: HttpErrorCode, status?: number);
17
+ }
18
+ export type FetchJsonOptions<T> = {
19
+ decode: (value: unknown) => T | Promise<T>;
20
+ fetch?: typeof globalThis.fetch;
21
+ signal?: AbortSignal;
22
+ timeoutMs?: number;
23
+ maxResponseBytes?: number;
24
+ request?: Omit<RequestInit, "signal">;
25
+ };
26
+ /** One bounded JSON request. Apps own URLs, credentials, cache policy, retries, and decoding. */
27
+ export declare function fetchJson<T>(url: string | URL, options: FetchJsonOptions<T>): Promise<T>;
28
+ export {};
29
+ //# sourceMappingURL=index.d.ts.map
package/dist/index.js ADDED
@@ -0,0 +1,134 @@
1
+ // src/index.ts
2
+ const messages = {
3
+ aborted: "Request canceled",
4
+ timeout: "Request timed out",
5
+ network: "Network request failed",
6
+ status: "HTTP request failed",
7
+ size: "Response exceeds the byte limit",
8
+ content_type: "Expected a UTF-8 JSON response",
9
+ json: "Invalid JSON response",
10
+ decode: "Response did not match the expected schema"
11
+ };
12
+ /** Safe diagnostics only: no URL, response body, headers, abort reason, or original cause. */
13
+ var HttpError = class extends Error {
14
+ code;
15
+ status;
16
+ constructor(code, status) {
17
+ super(messages[code]);
18
+ this.name = "HttpError";
19
+ this.code = code;
20
+ this.status = status;
21
+ }
22
+ };
23
+ async function cancelBody(body) {
24
+ try {
25
+ await body.cancel();
26
+ } catch {
27
+ return;
28
+ }
29
+ }
30
+ function isJsonContentType(header) {
31
+ const contentType = (header ?? "").toLowerCase();
32
+ const sections = [];
33
+ let sectionStart = 0;
34
+ let quoted = false;
35
+ let escaped = false;
36
+ for (let index = 0; index < contentType.length; index++) {
37
+ const character = contentType[index];
38
+ if (escaped) escaped = false;
39
+ else if (quoted && character === "\\") escaped = true;
40
+ else if (character === "\"") quoted = !quoted;
41
+ else if (!quoted && character === ";") {
42
+ sections.push(contentType.slice(sectionStart, index));
43
+ sectionStart = index + 1;
44
+ }
45
+ }
46
+ if (quoted) return false;
47
+ sections.push(contentType.slice(sectionStart));
48
+ const [mediaType, ...parameters] = sections;
49
+ if (!/^application\/(?:json|[a-z0-9!#$&^_.+-]+\+json)$/.test(mediaType?.trim() ?? "")) return false;
50
+ return parameters.every((parameter) => {
51
+ const [name, value, extra] = parameter.trim().split("=");
52
+ return name?.trim() !== "charset" || extra === void 0 && /^(?:utf-8|"utf-8")$/.test(value?.trim() ?? "");
53
+ });
54
+ }
55
+ /** One bounded JSON request. Apps own URLs, credentials, cache policy, retries, and decoding. */
56
+ async function fetchJson(url, options) {
57
+ const { decode, signal, timeoutMs = 1e4, maxResponseBytes = 1048576 } = options;
58
+ if (!Number.isInteger(timeoutMs) || timeoutMs < 1 || timeoutMs > 2147483647) throw new TypeError("timeoutMs must be an integer between 1 and 2147483647");
59
+ if (!Number.isSafeInteger(maxResponseBytes) || maxResponseBytes < 1) throw new TypeError("maxResponseBytes must be a positive safe integer");
60
+ if (signal?.aborted) throw new HttpError("aborted");
61
+ const controller = new AbortController();
62
+ let failure;
63
+ let rejectAbort = () => {};
64
+ const aborted = new Promise((_resolve, reject) => {
65
+ rejectAbort = reject;
66
+ });
67
+ function abort(code) {
68
+ if (failure) return;
69
+ failure = new HttpError(code);
70
+ rejectAbort(failure);
71
+ controller.abort();
72
+ }
73
+ const onAbort = () => abort("aborted");
74
+ signal?.addEventListener("abort", onAbort, { once: true });
75
+ const timer = setTimeout(() => abort("timeout"), timeoutMs);
76
+ let reader;
77
+ async function request() {
78
+ const response = await (options.fetch ?? globalThis.fetch)(url, {
79
+ ...options.request,
80
+ signal: controller.signal
81
+ });
82
+ if (failure) {
83
+ if (response.body) cancelBody(response.body);
84
+ throw failure;
85
+ }
86
+ reader = response.body?.getReader();
87
+ const chunks = [];
88
+ let byteLength = 0;
89
+ if (reader) while (true) {
90
+ const chunk = await reader.read();
91
+ if (failure) throw failure;
92
+ if (chunk.done) break;
93
+ byteLength += chunk.value.byteLength;
94
+ if (byteLength > maxResponseBytes) throw new HttpError("size", response.status);
95
+ if (response.ok && chunk.value.byteLength > 0) chunks.push(chunk.value);
96
+ }
97
+ if (!response.ok) throw new HttpError("status", response.status);
98
+ if (!isJsonContentType(response.headers.get("content-type"))) throw new HttpError("content_type", response.status);
99
+ const bytes = new Uint8Array(byteLength);
100
+ let offset = 0;
101
+ for (const chunk of chunks) {
102
+ bytes.set(chunk, offset);
103
+ offset += chunk.byteLength;
104
+ }
105
+ let value;
106
+ try {
107
+ value = JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(bytes));
108
+ } catch {
109
+ throw new HttpError("json", response.status);
110
+ }
111
+ try {
112
+ return await decode(value);
113
+ } catch {
114
+ throw new HttpError("decode", response.status);
115
+ }
116
+ }
117
+ try {
118
+ return await Promise.race([request(), aborted]);
119
+ } catch (error) {
120
+ if (failure) throw failure;
121
+ if (error instanceof HttpError) throw error;
122
+ throw new HttpError("network");
123
+ } finally {
124
+ clearTimeout(timer);
125
+ signal?.removeEventListener("abort", onAbort);
126
+ if (reader) {
127
+ cancelBody(reader);
128
+ reader.releaseLock();
129
+ }
130
+ }
131
+ }
132
+ export { HttpError, fetchJson };
133
+
134
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","names":[],"sources":["../src/index.ts"],"sourcesContent":["const messages = {\n aborted: \"Request canceled\",\n timeout: \"Request timed out\",\n network: \"Network request failed\",\n status: \"HTTP request failed\",\n size: \"Response exceeds the byte limit\",\n content_type: \"Expected a UTF-8 JSON response\",\n json: \"Invalid JSON response\",\n decode: \"Response did not match the expected schema\",\n} as const;\n\nexport type HttpErrorCode = keyof typeof messages;\n\n/** Safe diagnostics only: no URL, response body, headers, abort reason, or original cause. */\nexport class HttpError extends Error {\n readonly code: HttpErrorCode;\n readonly status?: number;\n\n constructor(code: HttpErrorCode, status?: number) {\n super(messages[code]);\n this.name = \"HttpError\";\n this.code = code;\n this.status = status;\n }\n}\n\nexport type FetchJsonOptions<T> = {\n decode: (value: unknown) => T | Promise<T>;\n fetch?: typeof globalThis.fetch;\n signal?: AbortSignal;\n timeoutMs?: number;\n maxResponseBytes?: number;\n request?: Omit<RequestInit, \"signal\">;\n};\n\nasync function cancelBody(\n body: ReadableStream<Uint8Array> | ReadableStreamDefaultReader<Uint8Array>,\n) {\n try {\n await body.cancel();\n } catch {\n return;\n }\n}\n\nfunction isJsonContentType(header: string | null) {\n const contentType = (header ?? \"\").toLowerCase();\n const sections: string[] = [];\n let sectionStart = 0;\n let quoted = false;\n let escaped = false;\n for (let index = 0; index < contentType.length; index++) {\n const character = contentType[index];\n if (escaped) {\n escaped = false;\n } else if (quoted && character === \"\\\\\") {\n escaped = true;\n } else if (character === '\"') {\n quoted = !quoted;\n } else if (!quoted && character === \";\") {\n sections.push(contentType.slice(sectionStart, index));\n sectionStart = index + 1;\n }\n }\n if (quoted) return false;\n sections.push(contentType.slice(sectionStart));\n const [mediaType, ...parameters] = sections;\n if (!/^application\\/(?:json|[a-z0-9!#$&^_.+-]+\\+json)$/.test(mediaType?.trim() ?? \"\"))\n return false;\n return parameters.every((parameter) => {\n const [name, value, extra] = parameter.trim().split(\"=\");\n return (\n name?.trim() !== \"charset\" ||\n (extra === undefined && /^(?:utf-8|\"utf-8\")$/.test(value?.trim() ?? \"\"))\n );\n });\n}\n\n/** One bounded JSON request. Apps own URLs, credentials, cache policy, retries, and decoding. */\nexport async function fetchJson<T>(url: string | URL, options: FetchJsonOptions<T>): Promise<T> {\n const { decode, signal, timeoutMs = 10_000, maxResponseBytes = 1_048_576 } = options;\n if (!Number.isInteger(timeoutMs) || timeoutMs < 1 || timeoutMs > 2_147_483_647)\n throw new TypeError(\"timeoutMs must be an integer between 1 and 2147483647\");\n if (!Number.isSafeInteger(maxResponseBytes) || maxResponseBytes < 1)\n throw new TypeError(\"maxResponseBytes must be a positive safe integer\");\n if (signal?.aborted) throw new HttpError(\"aborted\");\n\n const controller = new AbortController();\n let failure: HttpError | undefined;\n let rejectAbort: (error: HttpError) => void = () => {};\n const aborted = new Promise<never>((_resolve, reject) => {\n rejectAbort = reject;\n });\n function abort(code: \"aborted\" | \"timeout\") {\n if (failure) return;\n failure = new HttpError(code);\n rejectAbort(failure);\n controller.abort();\n }\n const onAbort = () => abort(\"aborted\");\n signal?.addEventListener(\"abort\", onAbort, { once: true });\n const timer = setTimeout(() => abort(\"timeout\"), timeoutMs);\n let reader: ReadableStreamDefaultReader<Uint8Array> | undefined;\n\n async function request() {\n const response = await (options.fetch ?? globalThis.fetch)(url, {\n ...options.request,\n signal: controller.signal,\n });\n if (failure) {\n if (response.body) void cancelBody(response.body);\n throw failure;\n }\n reader = response.body?.getReader();\n const chunks: Uint8Array[] = [];\n let byteLength = 0;\n if (reader) {\n while (true) {\n const chunk = await reader.read();\n if (failure) throw failure;\n if (chunk.done) break;\n byteLength += chunk.value.byteLength;\n if (byteLength > maxResponseBytes) throw new HttpError(\"size\", response.status);\n if (response.ok && chunk.value.byteLength > 0) chunks.push(chunk.value);\n }\n }\n if (!response.ok) throw new HttpError(\"status\", response.status);\n if (!isJsonContentType(response.headers.get(\"content-type\")))\n throw new HttpError(\"content_type\", response.status);\n const bytes = new Uint8Array(byteLength);\n let offset = 0;\n for (const chunk of chunks) {\n bytes.set(chunk, offset);\n offset += chunk.byteLength;\n }\n let value: unknown;\n try {\n value = JSON.parse(new TextDecoder(\"utf-8\", { fatal: true }).decode(bytes));\n } catch {\n throw new HttpError(\"json\", response.status);\n }\n try {\n return await decode(value);\n } catch {\n throw new HttpError(\"decode\", response.status);\n }\n }\n\n try {\n return await Promise.race([request(), aborted]);\n } catch (error) {\n if (failure) throw failure;\n if (error instanceof HttpError) throw error;\n throw new HttpError(\"network\");\n } finally {\n clearTimeout(timer);\n signal?.removeEventListener(\"abort\", onAbort);\n if (reader) {\n void cancelBody(reader);\n reader.releaseLock();\n }\n }\n}\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,33 @@
1
1
  {
2
2
  "name": "@littlejay/http",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
3
+ "version": "0.1.1",
4
+ "private": false,
5
+ "license": "MIT",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "https://github.com/jordan-a-young/little-jay.git",
9
+ "directory": "packages/http"
10
+ },
11
+ "files": [
12
+ "dist"
13
+ ],
14
+ "type": "module",
15
+ "exports": {
16
+ ".": {
17
+ "types": "./dist/index.d.ts",
18
+ "import": "./dist/index.js"
19
+ }
20
+ },
21
+ "publishConfig": {
22
+ "access": "public",
23
+ "registry": "https://registry.npmjs.org/"
24
+ },
25
+ "devDependencies": {
26
+ "typescript": "7.0.2",
27
+ "vite-plus": "1.5.0"
28
+ },
29
+ "scripts": {
30
+ "build": "vp pack",
31
+ "typecheck": "tsc -p tsconfig.json"
32
+ }
6
33
  }