-
Notifications
You must be signed in to change notification settings - Fork 21
Removing Undici Dependency #363
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: v4.x
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -8,7 +8,6 @@ import { Blob } from 'buffer'; | |
import { IncomingMessage } from 'http'; | ||
import * as stream from 'stream'; | ||
import { ReadableStream } from 'stream/web'; | ||
import { FormData, Headers, HeadersInit, Request as uRequest } from 'undici'; | ||
import { URLSearchParams } from 'url'; | ||
import { fromNullableMapping } from '../converters/fromRpcNullable'; | ||
import { fromRpcTypedData } from '../converters/fromRpcTypedData'; | ||
|
@@ -17,22 +16,22 @@ import { isDefined, nonNullProp } from '../utils/nonNull'; | |
import { extractHttpUserFromHeaders } from './extractHttpUserFromHeaders'; | ||
|
||
interface InternalHttpRequestInit extends RpcHttpData { | ||
undiciRequest?: uRequest; | ||
request?: Request; | ||
} | ||
|
||
export class HttpRequest implements types.HttpRequest { | ||
readonly query: URLSearchParams; | ||
readonly params: HttpRequestParams; | ||
|
||
#cachedUser?: HttpRequestUser | null; | ||
#uReq: uRequest; | ||
#req: Request; | ||
#init: InternalHttpRequestInit; | ||
|
||
constructor(init: InternalHttpRequestInit) { | ||
this.#init = init; | ||
|
||
let uReq = init.undiciRequest; | ||
if (!uReq) { | ||
let req = init.request; | ||
if (!req) { | ||
const url = nonNullProp(init, 'url'); | ||
|
||
let body: Buffer | string | undefined; | ||
|
@@ -42,33 +41,33 @@ export class HttpRequest implements types.HttpRequest { | |
body = init.body.string; | ||
} | ||
|
||
uReq = new uRequest(url, { | ||
req = new Request(url, { | ||
body, | ||
method: nonNullProp(init, 'method'), | ||
headers: fromNullableMapping(init.nullableHeaders, init.headers), | ||
}); | ||
} | ||
this.#uReq = uReq; | ||
this.#req = req; | ||
|
||
if (init.nullableQuery || init.query) { | ||
this.query = new URLSearchParams(fromNullableMapping(init.nullableQuery, init.query)); | ||
} else { | ||
this.query = new URL(this.#uReq.url).searchParams; | ||
this.query = new URL(this.#req.url).searchParams; | ||
} | ||
|
||
this.params = fromNullableMapping(init.nullableParams, init.params); | ||
} | ||
|
||
get url(): string { | ||
return this.#uReq.url; | ||
return this.#req.url; | ||
} | ||
|
||
get method(): string { | ||
return this.#uReq.method; | ||
return this.#req.method; | ||
} | ||
|
||
get headers(): Headers { | ||
return this.#uReq.headers; | ||
return this.#req.headers; | ||
} | ||
|
||
get user(): HttpRequestUser | null { | ||
|
@@ -79,37 +78,40 @@ export class HttpRequest implements types.HttpRequest { | |
return this.#cachedUser; | ||
} | ||
|
||
get body(): ReadableStream<any> | null { | ||
return this.#uReq.body; | ||
get body(): ReadableStream<Uint8Array> | null { | ||
// eslint-disable-next-line @typescript-eslint/no-unsafe-return | ||
return this.#req.body as any; // Type compatibility between global and Node.js ReadableStream | ||
} | ||
|
||
get bodyUsed(): boolean { | ||
return this.#uReq.bodyUsed; | ||
return this.#req.bodyUsed; | ||
} | ||
|
||
async arrayBuffer(): Promise<ArrayBuffer> { | ||
return this.#uReq.arrayBuffer(); | ||
return this.#req.arrayBuffer(); | ||
} | ||
|
||
// eslint-disable-next-line @typescript-eslint/require-await | ||
async blob(): Promise<Blob> { | ||
return this.#uReq.blob(); | ||
// eslint-disable-next-line @typescript-eslint/no-unsafe-return | ||
return this.#req.blob() as any; // Type compatibility with Node.js Blob | ||
} | ||
|
||
async formData(): Promise<FormData> { | ||
return this.#uReq.formData(); | ||
return this.#req.formData(); | ||
} | ||
|
||
async json(): Promise<unknown> { | ||
return this.#uReq.json(); | ||
return this.#req.json(); | ||
} | ||
|
||
async text(): Promise<string> { | ||
return this.#uReq.text(); | ||
return this.#req.text(); | ||
} | ||
|
||
clone(): HttpRequest { | ||
const newInit = structuredClone(this.#init); | ||
newInit.undiciRequest = this.#uReq.clone(); | ||
newInit.request = this.#req.clone(); | ||
return new HttpRequest(newInit); | ||
} | ||
} | ||
|
@@ -144,12 +146,14 @@ export function createStreamRequest( | |
headers = <HeadersInit>headersData; | ||
} | ||
|
||
const uReq = new uRequest(url, { | ||
body, | ||
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument | ||
const req = new Request(url, { | ||
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment | ||
body: body as any, // Node.js Readable stream compatibility | ||
duplex: 'half', | ||
method: nonNullProp(proxyReq, 'method'), | ||
headers, | ||
}); | ||
} as any); // Global Request constructor compatibility | ||
Comment on lines
+150
to
+156
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [nitpick] Casting the init object to Copilot uses AI. Check for mistakes. Positive FeedbackNegative Feedback |
||
|
||
const params: Record<string, string> = {}; | ||
for (const [key, rpcValue] of Object.entries(rpcParams)) { | ||
|
@@ -159,7 +163,7 @@ export function createStreamRequest( | |
} | ||
|
||
return new HttpRequest({ | ||
undiciRequest: uReq, | ||
request: req, | ||
params, | ||
}); | ||
} |
Original file line number | Diff line number | Diff line change | ||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
@@ -5,32 +5,39 @@ import * as types from '@azure/functions'; | |||||||||||||||
import { HttpResponseInit } from '@azure/functions'; | ||||||||||||||||
import { Blob } from 'buffer'; | ||||||||||||||||
import { ReadableStream } from 'stream/web'; | ||||||||||||||||
import { FormData, Headers, Response as uResponse, ResponseInit as uResponseInit } from 'undici'; | ||||||||||||||||
import { isDefined } from '../utils/nonNull'; | ||||||||||||||||
|
||||||||||||||||
interface InternalHttpResponseInit extends HttpResponseInit { | ||||||||||||||||
undiciResponse?: uResponse; | ||||||||||||||||
response?: Response; | ||||||||||||||||
} | ||||||||||||||||
|
||||||||||||||||
export class HttpResponse implements types.HttpResponse { | ||||||||||||||||
readonly cookies: types.Cookie[]; | ||||||||||||||||
readonly enableContentNegotiation: boolean; | ||||||||||||||||
|
||||||||||||||||
#uRes: uResponse; | ||||||||||||||||
#res: Response; | ||||||||||||||||
#init: InternalHttpResponseInit; | ||||||||||||||||
|
||||||||||||||||
constructor(init?: InternalHttpResponseInit) { | ||||||||||||||||
init ??= {}; | ||||||||||||||||
this.#init = init; | ||||||||||||||||
|
||||||||||||||||
if (init.undiciResponse) { | ||||||||||||||||
this.#uRes = init.undiciResponse; | ||||||||||||||||
if (init.response) { | ||||||||||||||||
this.#res = init.response; | ||||||||||||||||
} else { | ||||||||||||||||
const uResInit: uResponseInit = { status: init.status, headers: init.headers }; | ||||||||||||||||
const resInit: ResponseInit = { status: init.status, headers: init.headers }; | ||||||||||||||||
if (isDefined(init.jsonBody)) { | ||||||||||||||||
this.#uRes = uResponse.json(init.jsonBody, uResInit); | ||||||||||||||||
// Create JSON response manually for compatibility | ||||||||||||||||
const jsonHeaders = new Headers(resInit.headers); | ||||||||||||||||
if (!jsonHeaders.has('content-type')) { | ||||||||||||||||
jsonHeaders.set('content-type', 'application/json'); | ||||||||||||||||
} | ||||||||||||||||
this.#res = new Response(JSON.stringify(init.jsonBody), { | ||||||||||||||||
...resInit, | ||||||||||||||||
headers: jsonHeaders, | ||||||||||||||||
}); | ||||||||||||||||
} else { | ||||||||||||||||
this.#uRes = new uResponse(init.body, uResInit); | ||||||||||||||||
this.#res = new Response(init.body, resInit); | ||||||||||||||||
} | ||||||||||||||||
} | ||||||||||||||||
|
||||||||||||||||
|
@@ -39,44 +46,47 @@ export class HttpResponse implements types.HttpResponse { | |||||||||||||||
} | ||||||||||||||||
|
||||||||||||||||
get status(): number { | ||||||||||||||||
return this.#uRes.status; | ||||||||||||||||
return this.#res.status; | ||||||||||||||||
} | ||||||||||||||||
|
||||||||||||||||
get headers(): Headers { | ||||||||||||||||
return this.#uRes.headers; | ||||||||||||||||
return this.#res.headers; | ||||||||||||||||
} | ||||||||||||||||
|
||||||||||||||||
get body(): ReadableStream<any> | null { | ||||||||||||||||
return this.#uRes.body; | ||||||||||||||||
get body(): ReadableStream<Uint8Array> | null { | ||||||||||||||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-return | ||||||||||||||||
return this.#res.body as any; // Type compatibility between global and Node.js ReadableStream | ||||||||||||||||
} | ||||||||||||||||
Comment on lines
+56
to
59
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [nitpick] Avoid using
Suggested change
Copilot uses AI. Check for mistakes. Positive FeedbackNegative Feedback |
||||||||||||||||
|
||||||||||||||||
get bodyUsed(): boolean { | ||||||||||||||||
return this.#uRes.bodyUsed; | ||||||||||||||||
return this.#res.bodyUsed; | ||||||||||||||||
} | ||||||||||||||||
|
||||||||||||||||
async arrayBuffer(): Promise<ArrayBuffer> { | ||||||||||||||||
return this.#uRes.arrayBuffer(); | ||||||||||||||||
return this.#res.arrayBuffer(); | ||||||||||||||||
} | ||||||||||||||||
|
||||||||||||||||
// eslint-disable-next-line @typescript-eslint/require-await | ||||||||||||||||
async blob(): Promise<Blob> { | ||||||||||||||||
return this.#uRes.blob(); | ||||||||||||||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-return | ||||||||||||||||
return this.#res.blob() as any; // Type compatibility with Node.js Blob | ||||||||||||||||
} | ||||||||||||||||
|
||||||||||||||||
async formData(): Promise<FormData> { | ||||||||||||||||
return this.#uRes.formData(); | ||||||||||||||||
return this.#res.formData(); | ||||||||||||||||
} | ||||||||||||||||
|
||||||||||||||||
async json(): Promise<unknown> { | ||||||||||||||||
return this.#uRes.json(); | ||||||||||||||||
return this.#res.json(); | ||||||||||||||||
} | ||||||||||||||||
|
||||||||||||||||
async text(): Promise<string> { | ||||||||||||||||
return this.#uRes.text(); | ||||||||||||||||
return this.#res.text(); | ||||||||||||||||
} | ||||||||||||||||
|
||||||||||||||||
clone(): HttpResponse { | ||||||||||||||||
const newInit = structuredClone(this.#init); | ||||||||||||||||
newInit.undiciResponse = this.#uRes.clone(); | ||||||||||||||||
newInit.response = this.#res.clone(); | ||||||||||||||||
return new HttpResponse(newInit); | ||||||||||||||||
} | ||||||||||||||||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[nitpick] Using
any
here bypasses type checks; consider creating a proper type guard or wrapper for the request body stream to keep type safety.Copilot uses AI. Check for mistakes.