From 843c9966ec127e4b63ab0a154f1d95d8540a59fa Mon Sep 17 00:00:00 2001 From: David Sherret Date: Fri, 21 Nov 2025 11:21:48 -0500 Subject: [PATCH 1/3] fix: update for Uint8Array being generic --- body.ts | 8 ++++---- http_server_bun.ts | 4 ++-- http_server_native_request.ts | 4 ++-- http_server_node.ts | 10 +++++----- send.ts | 10 +++++----- types.ts | 6 +++--- 6 files changed, 21 insertions(+), 21 deletions(-) diff --git a/body.ts b/body.ts index ef32b6f6..bc82e494 100644 --- a/body.ts +++ b/body.ts @@ -30,13 +30,13 @@ const KNOWN_BODY_TYPES: [bodyType: BodyType, knownMediaTypes: string[]][] = [ ]; async function readBlob( - body?: ReadableStream | null, + body?: ReadableStream> | null, type?: string | null, ): Promise { if (!body) { return new Blob(undefined, type ? { type } : undefined); } - const chunks: Uint8Array[] = []; + const chunks: Uint8Array[] = []; for await (const chunk of body) { chunks.push(chunk); } @@ -45,7 +45,7 @@ async function readBlob( /** An object which encapsulates information around a request body. */ export class Body { - #body?: ReadableStream | null; + #body?: ReadableStream> | null; #memo: Promise | null = null; #memoType: "arrayBuffer" | "blob" | "formData" | "text" | null = null; #headers?: Headers; @@ -80,7 +80,7 @@ export class Body { } /** Exposes the "raw" `ReadableStream` of the body. */ - get stream(): ReadableStream | null { + get stream(): ReadableStream> | null { return this.#request ? this.#request.body : this.#body!; } diff --git a/http_server_bun.ts b/http_server_bun.ts index 8fd089cb..62813962 100644 --- a/http_server_bun.ts +++ b/http_server_bun.ts @@ -94,7 +94,7 @@ class BunRequest implements ServerRequest { #resolved = false; #promise: Promise; - get body(): ReadableStream | null { + get body(): ReadableStream> | null { return this.#request.body; } @@ -150,7 +150,7 @@ class BunRequest implements ServerRequest { this.#reject(reason); } - getBody(): ReadableStream | null { + getBody(): ReadableStream> | null { return this.#request.body; } diff --git a/http_server_native_request.ts b/http_server_native_request.ts index ae9a3a24..c4229a66 100644 --- a/http_server_native_request.ts +++ b/http_server_native_request.ts @@ -55,7 +55,7 @@ export class NativeRequest implements ServerRequest { this.#response = promise; } - get body(): ReadableStream | null { + get body(): ReadableStream> | null { return this.#request.body; } @@ -102,7 +102,7 @@ export class NativeRequest implements ServerRequest { this.#resolved = true; } - getBody(): ReadableStream | null { + getBody(): ReadableStream> | null { return this.#request.body; } diff --git a/http_server_node.ts b/http_server_node.ts index 24d76e51..446b3669 100644 --- a/http_server_node.ts +++ b/http_server_node.ts @@ -90,15 +90,15 @@ export class NodeRequest implements ServerRequest { this.#responded = true; } - getBody(): ReadableStream | null { - let body: ReadableStream | null; + getBody(): ReadableStream> | null { + let body: ReadableStream> | null; if (this.method === "GET" || this.method === "HEAD") { body = null; } else { - body = new ReadableStream({ + body = new ReadableStream>({ start: (controller) => { - this.#request.on("data", (chunk: Uint8Array) => { - controller.enqueue(chunk); + this.#request.on("data", (chunk) => { + controller.enqueue(chunk as Uint8Array); }); this.#request.on("error", (err: Error) => { controller.error(err); diff --git a/send.ts b/send.ts index 4b343e0e..5cb37a59 100644 --- a/send.ts +++ b/send.ts @@ -137,9 +137,9 @@ async function getEntity( stats: Deno.FileInfo, maxbuffer: number, response: Response, -): Promise<[Uint8Array | Deno.FsFile, Uint8Array | FileInfo, FileInfo]> { - let body: Uint8Array | Deno.FsFile; - let entity: Uint8Array | FileInfo; +): Promise<[Uint8Array | Deno.FsFile, Uint8Array | FileInfo, FileInfo]> { + let body: Uint8Array | Deno.FsFile; + let entity: Uint8Array | FileInfo; const fileInfo = { mtime: new Date(mtime), size: stats.size }; if (stats.size < maxbuffer) { const buffer = await Deno.readFile(path); @@ -270,8 +270,8 @@ export async function send( : contentTypes[extname(path)] ?? extname(path); } - let entity: Uint8Array | FileInfo | null = null; - let body: Uint8Array | Deno.FsFile | null = null; + let entity: Uint8Array | FileInfo | null = null; + let body: Uint8Array | Deno.FsFile | null = null; let fileInfo: FileInfo | null = null; if (request.headers.has("If-None-Match") && mtime) { diff --git a/types.ts b/types.ts index f9f0314a..e7d1282a 100644 --- a/types.ts +++ b/types.ts @@ -21,7 +21,7 @@ export interface ServerRequest { readonly url: string; // deno-lint-ignore no-explicit-any error(reason?: any): void; - getBody(): ReadableStream | null; + getBody(): ReadableStream> | null; respond(response: Response): void | Promise; upgrade?(options?: UpgradeWebSocketOptions): WebSocket; } @@ -38,8 +38,8 @@ export interface ServerConstructor { type?: "native" | "node" | "bun"; } -export type Data = string | number[] | ArrayBuffer | Uint8Array; -export type Key = string | number[] | ArrayBuffer | Uint8Array; +export type Data = string | number[] | ArrayBuffer | Uint8Array; +export type Key = string | number[] | ArrayBuffer | Uint8Array; export interface UpgradeWebSocketOptions { protocol?: string; From ff8721f75813bb4b270d46365fae786a093111a9 Mon Sep 17 00:00:00 2001 From: David Sherret Date: Fri, 21 Nov 2025 11:27:48 -0500 Subject: [PATCH 2/3] fix: update for Uint8Array being generic --- body.ts | 10 +++++----- http_server_bun.ts | 5 +++-- http_server_native_request.ts | 5 +++-- http_server_node.ts | 9 +++++---- send.ts | 17 ++++++++++++----- types.ts | 9 ++++++--- 6 files changed, 34 insertions(+), 21 deletions(-) diff --git a/body.ts b/body.ts index bc82e494..d7da3f9b 100644 --- a/body.ts +++ b/body.ts @@ -9,7 +9,7 @@ */ import { createHttpError, matches, parseFormData, Status } from "./deps.ts"; -import type { ServerRequest } from "./types.ts"; +import type { ServerRequest, Uint8ArrayArrayBuffer } from "./types.ts"; type JsonReviver = (key: string, value: unknown) => unknown; @@ -30,13 +30,13 @@ const KNOWN_BODY_TYPES: [bodyType: BodyType, knownMediaTypes: string[]][] = [ ]; async function readBlob( - body?: ReadableStream> | null, + body?: ReadableStream | null, type?: string | null, ): Promise { if (!body) { return new Blob(undefined, type ? { type } : undefined); } - const chunks: Uint8Array[] = []; + const chunks: Uint8ArrayArrayBuffer[] = []; for await (const chunk of body) { chunks.push(chunk); } @@ -45,7 +45,7 @@ async function readBlob( /** An object which encapsulates information around a request body. */ export class Body { - #body?: ReadableStream> | null; + #body?: ReadableStream | null; #memo: Promise | null = null; #memoType: "arrayBuffer" | "blob" | "formData" | "text" | null = null; #headers?: Headers; @@ -80,7 +80,7 @@ export class Body { } /** Exposes the "raw" `ReadableStream` of the body. */ - get stream(): ReadableStream> | null { + get stream(): ReadableStream | null { return this.#request ? this.#request.body : this.#body!; } diff --git a/http_server_bun.ts b/http_server_bun.ts index 62813962..41d74c3a 100644 --- a/http_server_bun.ts +++ b/http_server_bun.ts @@ -13,6 +13,7 @@ import type { ServeOptions, ServerRequest, ServeTlsOptions, + Uint8ArrayArrayBuffer, } from "./types.ts"; import { createPromiseWithResolvers } from "./utils/create_promise_with_resolvers.ts"; @@ -94,7 +95,7 @@ class BunRequest implements ServerRequest { #resolved = false; #promise: Promise; - get body(): ReadableStream> | null { + get body(): ReadableStream | null { return this.#request.body; } @@ -150,7 +151,7 @@ class BunRequest implements ServerRequest { this.#reject(reason); } - getBody(): ReadableStream> | null { + getBody(): ReadableStream | null { return this.#request.body; } diff --git a/http_server_native_request.ts b/http_server_native_request.ts index c4229a66..09996429 100644 --- a/http_server_native_request.ts +++ b/http_server_native_request.ts @@ -3,6 +3,7 @@ import type { NetAddr, ServerRequest, + Uint8ArrayArrayBuffer, UpgradeWebSocketFn, UpgradeWebSocketOptions, } from "./types.ts"; @@ -55,7 +56,7 @@ export class NativeRequest implements ServerRequest { this.#response = promise; } - get body(): ReadableStream> | null { + get body(): ReadableStream | null { return this.#request.body; } @@ -102,7 +103,7 @@ export class NativeRequest implements ServerRequest { this.#resolved = true; } - getBody(): ReadableStream> | null { + getBody(): ReadableStream | null { return this.#request.body; } diff --git a/http_server_node.ts b/http_server_node.ts index 446b3669..84193bd6 100644 --- a/http_server_node.ts +++ b/http_server_node.ts @@ -12,6 +12,7 @@ import type { ServeOptions, ServerRequest, ServeTlsOptions, + Uint8ArrayArrayBuffer, } from "./types.ts"; import { createPromiseWithResolvers } from "./utils/create_promise_with_resolvers.ts"; @@ -90,15 +91,15 @@ export class NodeRequest implements ServerRequest { this.#responded = true; } - getBody(): ReadableStream> | null { - let body: ReadableStream> | null; + getBody(): ReadableStream | null { + let body: ReadableStream | null; if (this.method === "GET" || this.method === "HEAD") { body = null; } else { - body = new ReadableStream>({ + body = new ReadableStream({ start: (controller) => { this.#request.on("data", (chunk) => { - controller.enqueue(chunk as Uint8Array); + controller.enqueue(chunk as Uint8ArrayArrayBuffer); }); this.#request.on("error", (err: Error) => { controller.error(err); diff --git a/send.ts b/send.ts index 5cb37a59..e4a33851 100644 --- a/send.ts +++ b/send.ts @@ -31,6 +31,7 @@ import type { Response } from "./response.ts"; import { isNode } from "./utils/type_guards.ts"; import { decode } from "./utils/decode.ts"; import { resolvePath } from "./utils/resolve_path.ts"; +import type { Uint8ArrayArrayBuffer } from "./types.ts"; if (isNode()) { console.warn("oak send() does not work under Node.js."); @@ -137,9 +138,15 @@ async function getEntity( stats: Deno.FileInfo, maxbuffer: number, response: Response, -): Promise<[Uint8Array | Deno.FsFile, Uint8Array | FileInfo, FileInfo]> { - let body: Uint8Array | Deno.FsFile; - let entity: Uint8Array | FileInfo; +): Promise< + [ + Uint8ArrayArrayBuffer | Deno.FsFile, + Uint8ArrayArrayBuffer | FileInfo, + FileInfo, + ] +> { + let body: Uint8ArrayArrayBuffer | Deno.FsFile; + let entity: Uint8ArrayArrayBuffer | FileInfo; const fileInfo = { mtime: new Date(mtime), size: stats.size }; if (stats.size < maxbuffer) { const buffer = await Deno.readFile(path); @@ -270,8 +277,8 @@ export async function send( : contentTypes[extname(path)] ?? extname(path); } - let entity: Uint8Array | FileInfo | null = null; - let body: Uint8Array | Deno.FsFile | null = null; + let entity: Uint8ArrayArrayBuffer | FileInfo | null = null; + let body: Uint8ArrayArrayBuffer | Deno.FsFile | null = null; let fileInfo: FileInfo | null = null; if (request.headers.has("If-None-Match") && mtime) { diff --git a/types.ts b/types.ts index e7d1282a..4c261cb6 100644 --- a/types.ts +++ b/types.ts @@ -21,7 +21,7 @@ export interface ServerRequest { readonly url: string; // deno-lint-ignore no-explicit-any error(reason?: any): void; - getBody(): ReadableStream> | null; + getBody(): ReadableStream | null; respond(response: Response): void | Promise; upgrade?(options?: UpgradeWebSocketOptions): WebSocket; } @@ -38,8 +38,11 @@ export interface ServerConstructor { type?: "native" | "node" | "bun"; } -export type Data = string | number[] | ArrayBuffer | Uint8Array; -export type Key = string | number[] | ArrayBuffer | Uint8Array; +/** Type for backwards compatibility. Resolves to `Uint8Array` in + * TypeScript 5.7+ and `Uint8Array` in older versions. */ +export type Uint8ArrayArrayBuffer = ReturnType; +export type Data = string | number[] | ArrayBuffer | Uint8ArrayArrayBuffer; +export type Key = string | number[] | ArrayBuffer | Uint8ArrayArrayBuffer; export interface UpgradeWebSocketOptions { protocol?: string; From 403ea29e3a9c12f5625b58084b5ab305e2411a45 Mon Sep 17 00:00:00 2001 From: David Sherret Date: Fri, 21 Nov 2025 11:29:25 -0500 Subject: [PATCH 3/3] lint --- deno.json | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/deno.json b/deno.json index 52cf4887..c86d42c6 100644 --- a/deno.json +++ b/deno.json @@ -40,5 +40,10 @@ "fmt": { "exclude": ["README.md"] }, + "lint": { + "rules": { + "exclude": ["no-import-prefix"] + } + }, "lock": false }