@statewalker/webrun-http-streams 0.1.1 → 0.2.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.
Files changed (55) hide show
  1. package/README.md +288 -11
  2. package/dist/bytes.d.ts +43 -0
  3. package/dist/bytes.d.ts.map +1 -0
  4. package/dist/codec-default.d.ts +7 -0
  5. package/dist/codec-default.d.ts.map +1 -0
  6. package/dist/duplex-site-builder.d.ts +3 -0
  7. package/dist/duplex-site-builder.d.ts.map +1 -1
  8. package/dist/envelope.d.ts +10 -10
  9. package/dist/envelope.d.ts.map +1 -1
  10. package/dist/fetch.d.ts +3 -2
  11. package/dist/fetch.d.ts.map +1 -1
  12. package/dist/http-data.d.ts +11 -7
  13. package/dist/http-data.d.ts.map +1 -1
  14. package/dist/http-error.d.ts.map +1 -1
  15. package/dist/http-stubs.d.ts +12 -0
  16. package/dist/http-stubs.d.ts.map +1 -1
  17. package/dist/http1/chunked.d.ts +18 -0
  18. package/dist/http1/chunked.d.ts.map +1 -0
  19. package/dist/http1/decode.d.ts +5 -0
  20. package/dist/http1/decode.d.ts.map +1 -0
  21. package/dist/http1/encode.d.ts +20 -0
  22. package/dist/http1/encode.d.ts.map +1 -0
  23. package/dist/http1/errors.d.ts +9 -0
  24. package/dist/http1/errors.d.ts.map +1 -0
  25. package/dist/http1/headers.d.ts +78 -0
  26. package/dist/http1/headers.d.ts.map +1 -0
  27. package/dist/http1/index.d.ts +18 -0
  28. package/dist/http1/index.d.ts.map +1 -0
  29. package/dist/index.d.ts +6 -2
  30. package/dist/index.d.ts.map +1 -1
  31. package/dist/index.js +1039 -137
  32. package/dist/message.d.ts +50 -0
  33. package/dist/message.d.ts.map +1 -0
  34. package/dist/request-streams.d.ts +52 -0
  35. package/dist/request-streams.d.ts.map +1 -0
  36. package/dist/sniff.d.ts +18 -0
  37. package/dist/sniff.d.ts.map +1 -0
  38. package/package.json +8 -6
  39. package/src/bytes.ts +157 -0
  40. package/src/codec-default.ts +13 -0
  41. package/src/duplex-site-builder.ts +9 -1
  42. package/src/envelope.ts +43 -34
  43. package/src/fetch.ts +130 -12
  44. package/src/http-data.ts +160 -17
  45. package/src/http-stubs.ts +72 -18
  46. package/src/http1/chunked.ts +89 -0
  47. package/src/http1/decode.ts +208 -0
  48. package/src/http1/encode.ts +181 -0
  49. package/src/http1/errors.ts +8 -0
  50. package/src/http1/headers.ts +263 -0
  51. package/src/http1/index.ts +40 -0
  52. package/src/index.ts +18 -0
  53. package/src/message.ts +62 -0
  54. package/src/request-streams.ts +75 -0
  55. package/src/sniff.ts +68 -0
@@ -0,0 +1,78 @@
1
+ import type { ByteReader } from "../bytes.js";
2
+ export type HeaderList = [string, string][];
3
+ export declare function isTokenChar(byte: number): boolean;
4
+ export declare function isToken(value: string): boolean;
5
+ /**
6
+ * Header bytes are latin-1: byte-preserving, matching Node, and lossless
7
+ * across a decode/encode round-trip. Control characters are rejected
8
+ * separately by `assertValidHeaderValue`.
9
+ */
10
+ export declare function decodeLatin1(bytes: Uint8Array): string;
11
+ export declare function encodeLatin1(text: string): Uint8Array;
12
+ /**
13
+ * Validates a value that is about to become (or was read as) a `Host`
14
+ * header: untrusted input either way, so an unrecognised shape is a refusal,
15
+ * not a guess. Rejects a present-but-empty value, one carrying userinfo
16
+ * (`evil.com@good.com`), and — the reason this also runs on encode — one
17
+ * smuggling a CRLF-terminated line into the authority of a caller-supplied
18
+ * url. Never applied to trusted configuration (a codec's `opts.host`).
19
+ */
20
+ export declare function assertValidHost(host: string): void;
21
+ /**
22
+ * A request-target must be entirely visible ASCII (RFC 9110 VCHAR) — nothing
23
+ * `<= 0x20` (space and every control character, CR/LF included) and nothing
24
+ * `>= 0x7F` (DEL and beyond). Applied on encode (`splitTarget`, so a
25
+ * caller-supplied url can never inject a second request line) and on decode
26
+ * (so a relay that decodes then re-encodes can never put an embedded control
27
+ * character back on the wire).
28
+ */
29
+ export declare function assertValidTarget(target: string): void;
30
+ export declare function assertValidHeaderValue(name: string, value: string): void;
31
+ /** Same character class as a header value (M5) — CR/LF, every C0 control, and DEL. */
32
+ export declare function assertValidStatusText(value: string): void;
33
+ export declare function encodeHeaderLines(headers: HeaderList): string;
34
+ /**
35
+ * Read to the blank line. `alreadyUsed` is the byte count of the start line,
36
+ * so the bound covers the whole head section rather than the headers alone.
37
+ */
38
+ export declare function readHeaderSection(reader: ByteReader, maxHeaderBytes: number, alreadyUsed: number): Promise<HeaderList>;
39
+ export declare function getAll(headers: HeaderList, name: string): string[];
40
+ export declare function withoutHeaders(headers: HeaderList, names: string[]): HeaderList;
41
+ /**
42
+ * Parse a `Content-Length` field into a single validated value.
43
+ *
44
+ * RFC 9110 §8.6 permits the value to be a comma-separated list of identical
45
+ * numbers (a relay may have appended one), so the list is folded; differing
46
+ * values are a refusal, not a choice. Shared by `resolveFraming` on decode and
47
+ * by the encoder's declared-length check, which previously carried its own
48
+ * copy that did NOT split on commas — so decode accepted `5, 5` while encode
49
+ * rejected it, and a relay that decoded then re-encoded threw.
50
+ *
51
+ * Returns undefined when the field is absent.
52
+ */
53
+ export declare function parseContentLength(values: string[]): number | undefined;
54
+ /**
55
+ * Statuses that carry no body whatever the headers say (RFC 9110 §8.6): 1xx,
56
+ * 204 and 304. Defined once because the encoder must not frame a body for
57
+ * them and the decoder must not try to read one — two lists that agreed today
58
+ * and were free to drift tomorrow.
59
+ *
60
+ * A response to HEAD is also bodyless, but that depends on the request rather
61
+ * than the status, so callers test it separately.
62
+ */
63
+ export declare function isBodylessStatus(status: number): boolean;
64
+ export type BodyFraming = {
65
+ kind: "chunked";
66
+ } | {
67
+ kind: "length";
68
+ length: number;
69
+ } | {
70
+ kind: "none";
71
+ };
72
+ /**
73
+ * RFC 9112 §6.3, with every ambiguity turned into a refusal. In particular a
74
+ * message declaring both Content-Length and Transfer-Encoding is rejected
75
+ * rather than resolved — disagreeing on which one wins is request smuggling.
76
+ */
77
+ export declare function resolveFraming(headers: HeaderList, version: string): BodyFraming;
78
+ //# sourceMappingURL=headers.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"headers.d.ts","sourceRoot":"","sources":["../../src/http1/headers.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAG9C,MAAM,MAAM,UAAU,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,CAAC;AAS5C,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAEjD;AAED,wBAAgB,OAAO,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAM9C;AAED;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,UAAU,GAAG,MAAM,CAItD;AAED,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,UAAU,CAUrD;AAUD;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAIlD;AAED;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAOtD;AAwBD,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAExE;AAED,sFAAsF;AACtF,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAEzD;AAED,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,UAAU,GAAG,MAAM,CAQ7D;AAED;;;GAGG;AACH,wBAAsB,iBAAiB,CACrC,MAAM,EAAE,UAAU,EAClB,cAAc,EAAE,MAAM,EACtB,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC,UAAU,CAAC,CA6BrB;AAED,wBAAgB,MAAM,CAAC,OAAO,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CAGlE;AAED,wBAAgB,cAAc,CAAC,OAAO,EAAE,UAAU,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,UAAU,CAG/E;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,GAAG,SAAS,CAkBvE;AAED;;;;;;;;GAQG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAExD;AAED,MAAM,MAAM,WAAW,GACnB;IAAE,IAAI,EAAE,SAAS,CAAA;CAAE,GACnB;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GAClC;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC;AAErB;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,UAAU,EAAE,OAAO,EAAE,MAAM,GAAG,WAAW,CA+BhF"}
@@ -0,0 +1,18 @@
1
+ import type { MessageCodec } from "../message.js";
2
+ export type HttpCodecOptions = {
3
+ /**
4
+ * Scheme used to rebuild an absolute url on decode. HTTP/1.1 origin-form
5
+ * carries no scheme, so this is configuration, not wire data — a peer
6
+ * configured `http` rebuilds an `https` url as `http`. Accepted cost of
7
+ * decision 6; see ADR-0006.
8
+ */
9
+ scheme?: "http" | "https";
10
+ /** Authority used when a url carries none. Also fills the mandatory Host header. */
11
+ host?: string;
12
+ /** Bound on the whole head section, start line included. Default 65536. */
13
+ maxHeaderBytes?: number;
14
+ };
15
+ export declare function newHttpCodec(options?: HttpCodecOptions): MessageCodec;
16
+ export declare const httpCodec: MessageCodec;
17
+ export { HttpParseError } from "./errors.js";
18
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/http1/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAKlD,MAAM,MAAM,gBAAgB,GAAG;IAC7B;;;;;OAKG;IACH,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;IAC1B,oFAAoF;IACpF,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,2EAA2E;IAC3E,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB,CAAC;AAEF,wBAAgB,YAAY,CAAC,OAAO,GAAE,gBAAqB,GAAG,YAAY,CAiBzE;AAED,eAAO,MAAM,SAAS,EAAE,YAA6B,CAAC;AACtD,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC"}
package/dist/index.d.ts CHANGED
@@ -1,7 +1,11 @@
1
+ export { defaultCodec } from "./codec-default.js";
1
2
  export { DuplexSiteBuilder, type SiteHandler } from "./duplex-site-builder.js";
2
- export { decodeMessage, encodeMessage, type RequestEnvelope, type ResponseEnvelope, } from "./envelope.js";
3
+ export { decodeMessage, encodeMessage, jsonEnvelopeCodec, type RequestEnvelope, type ResponseEnvelope, } from "./envelope.js";
3
4
  export { fetchOverDuplex, serveFetchOverDuplex } from "./fetch.js";
4
- export { type HttpDataHandler, type HttpDataHandlerResult, type HttpFetchResult, httpFetch, httpServe, } from "./http-data.js";
5
+ export { type HttpDataHandler, type HttpDataHandlerResult, type HttpDataOptions, type HttpFetchResult, httpFetch, httpServe, PEER_ERROR_HEADER, } from "./http-data.js";
5
6
  export { HttpError, type HttpErrorOptions } from "./http-error.js";
6
7
  export { type HttpHandler, newHttpClientStub, newHttpServerStub, type SerializedHttpEnvelope, type SerializedHttpRequest, type SerializedHttpResponse, } from "./http-stubs.js";
8
+ export { type HttpCodecOptions, HttpParseError, httpCodec, newHttpCodec, } from "./http1/index.js";
9
+ export type { ByteSource, DecodedRequest, DecodedResponse, MessageCodec, ResponseCodecOptions, } from "./message.js";
10
+ export { newSniffingCodec, type SniffingCodecOptions } from "./sniff.js";
7
11
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,KAAK,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAC/E,OAAO,EACL,aAAa,EACb,aAAa,EACb,KAAK,eAAe,EACpB,KAAK,gBAAgB,GACtB,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,eAAe,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAC;AACnE,OAAO,EACL,KAAK,eAAe,EACpB,KAAK,qBAAqB,EAC1B,KAAK,eAAe,EACpB,SAAS,EACT,SAAS,GACV,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,SAAS,EAAE,KAAK,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AACnE,OAAO,EACL,KAAK,WAAW,EAChB,iBAAiB,EACjB,iBAAiB,EACjB,KAAK,sBAAsB,EAC3B,KAAK,qBAAqB,EAC1B,KAAK,sBAAsB,GAC5B,MAAM,iBAAiB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,iBAAiB,EAAE,KAAK,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAC/E,OAAO,EACL,aAAa,EACb,aAAa,EACb,iBAAiB,EACjB,KAAK,eAAe,EACpB,KAAK,gBAAgB,GACtB,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,eAAe,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAC;AACnE,OAAO,EACL,KAAK,eAAe,EACpB,KAAK,qBAAqB,EAC1B,KAAK,eAAe,EACpB,KAAK,eAAe,EACpB,SAAS,EACT,SAAS,EACT,iBAAiB,GAClB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,SAAS,EAAE,KAAK,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AACnE,OAAO,EACL,KAAK,WAAW,EAChB,iBAAiB,EACjB,iBAAiB,EACjB,KAAK,sBAAsB,EAC3B,KAAK,qBAAqB,EAC1B,KAAK,sBAAsB,GAC5B,MAAM,iBAAiB,CAAC;AACzB,OAAO,EACL,KAAK,gBAAgB,EACrB,cAAc,EACd,SAAS,EACT,YAAY,GACb,MAAM,kBAAkB,CAAC;AAC1B,YAAY,EACV,UAAU,EACV,cAAc,EACd,eAAe,EACf,YAAY,EACZ,oBAAoB,GACrB,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,gBAAgB,EAAE,KAAK,oBAAoB,EAAE,MAAM,YAAY,CAAC"}