Skip to content

Commit

Permalink
Improvements on types
Browse files Browse the repository at this point in the history
  • Loading branch information
ardatan committed Feb 25, 2025
1 parent 6ffce09 commit d59e1ff
Show file tree
Hide file tree
Showing 7 changed files with 51 additions and 49 deletions.
3 changes: 2 additions & 1 deletion packages/disposablestack/tests/disposablestack.spec.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { describe, expect, it, jest } from '@jest/globals';
import { MaybePromise } from '@whatwg-node/promise-helpers';
import { AsyncDisposableStack, DisposableStack, DisposableSymbols, patchSymbols } from '../src';

function createTestCases<
Expand All @@ -11,7 +12,7 @@ function createTestCases<
): Record<
string,
{
run(stack: TStack, disposeFn: jest.Mock): void | Promise<void>;
run(stack: TStack, disposeFn: jest.Mock): MaybePromise<void>;
check(disposeFn: jest.Mock): void;
}
> {
Expand Down
12 changes: 6 additions & 6 deletions packages/promise-helpers/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,18 +14,18 @@ export function handleMaybePromiseLike<TInput, TOutput>(
outputSuccessFactory: (value: TInput) => MaybePromiseLike<TOutput>,
outputErrorFactory?: (err: any) => MaybePromiseLike<TOutput>,
): MaybePromiseLike<TOutput> {
function _handle() {
function _handleMaybePromiseLike() {
const input$ = inputFactory();
if (isPromiseLike(input$)) {
return input$.then(outputSuccessFactory, outputErrorFactory);
}
return outputSuccessFactory(input$);
}
if (!outputErrorFactory) {
return _handle();
return _handleMaybePromiseLike();
}
try {
return _handle();
return _handleMaybePromiseLike();
} catch (err) {
return outputErrorFactory(err);
}
Expand Down Expand Up @@ -106,14 +106,14 @@ export function createDeferredPromise<T = void>(): DeferredPromise<T> {

export function iterateAsyncVoid<TInput>(
iterable: Iterable<TInput>,
callback: (input: TInput, stopEarly: () => void) => Promise<void> | void,
): Promise<void> | void {
callback: (input: TInput, stopEarly: () => void) => MaybePromise<void>,
): MaybePromise<void> {
const iterator = iterable[Symbol.iterator]();
let stopEarlyFlag = false;
function stopEarlyFn() {
stopEarlyFlag = true;
}
function iterate(): Promise<void> | void {
function iterate(): MaybePromise<void> {
const { done: endOfIterator, value } = iterator.next();
if (endOfIterator) {
return;
Expand Down
2 changes: 1 addition & 1 deletion packages/server/src/createServerAdapter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -402,7 +402,7 @@ function createServerAdapter<
| ({ request: Request } & Partial<TServerContext>)
| UWSResponse,
...maybeCtx: Partial<TServerContext>[]
): Promise<Response> | Response | Promise<void> | void => {
): MaybePromise<Response> | Promise<void> | void => {

Check failure on line 405 in packages/server/src/createServerAdapter.ts

View workflow job for this annotation

GitHub Actions / server (native)

Cannot find name 'MaybePromise'.

Check failure on line 405 in packages/server/src/createServerAdapter.ts

View workflow job for this annotation

GitHub Actions / e2e / aws-lambda

Cannot find name 'MaybePromise'.

Check failure on line 405 in packages/server/src/createServerAdapter.ts

View workflow job for this annotation

GitHub Actions / server (ponyfill)

Cannot find name 'MaybePromise'.

Check failure on line 405 in packages/server/src/createServerAdapter.ts

View workflow job for this annotation

GitHub Actions / esm

Cannot find name 'MaybePromise'.

Check failure on line 405 in packages/server/src/createServerAdapter.ts

View workflow job for this annotation

GitHub Actions / e2e / azure-function

Cannot find name 'MaybePromise'.

Check failure on line 405 in packages/server/src/createServerAdapter.ts

View workflow job for this annotation

GitHub Actions / server (undici)

Cannot find name 'MaybePromise'.

Check failure on line 405 in packages/server/src/createServerAdapter.ts

View workflow job for this annotation

GitHub Actions / e2e / cloudflare-workers

Cannot find name 'MaybePromise'.

Check failure on line 405 in packages/server/src/createServerAdapter.ts

View workflow job for this annotation

GitHub Actions / type check

Cannot find name 'MaybePromise'.

Check failure on line 405 in packages/server/src/createServerAdapter.ts

View workflow job for this annotation

GitHub Actions / e2e / cloudflare-modules

Cannot find name 'MaybePromise'.

Check failure on line 405 in packages/server/src/createServerAdapter.ts

View workflow job for this annotation

GitHub Actions / alpha / snapshot

Cannot find name 'MaybePromise'.
// If it is a Node request
const [initOrCtxOrRes, ...restOfCtx] = maybeCtx;

Expand Down
30 changes: 18 additions & 12 deletions packages/server/src/plugins/useCors.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { handleMaybePromise, MaybePromise } from '@whatwg-node/promise-helpers';
import type { ServerAdapterPlugin } from './types.js';

export type CORSOptions =
Expand All @@ -21,7 +22,7 @@ export type CORSOptionsFactory<TServerContext> = (
...args: {} extends TServerContext
? [serverContext?: TServerContext | undefined]
: [serverContext: TServerContext]
) => CORSOptions | Promise<CORSOptions>;
) => MaybePromise<CORSOptions>;

export function getCORSHeadersByRequestAndOptions(
request: Request,
Expand Down Expand Up @@ -102,14 +103,15 @@ export function getCORSHeadersByRequestAndOptions(
return headers;
}

async function getCORSResponseHeaders<TServerContext>(
function getCORSResponseHeaders<TServerContext>(
request: Request,
corsOptionsFactory: CORSOptionsFactory<TServerContext>,
serverContext: TServerContext,
) {
const corsOptions = await corsOptionsFactory(request, serverContext);

return getCORSHeadersByRequestAndOptions(request, corsOptions);
return handleMaybePromise(
() => corsOptionsFactory(request, serverContext),
corsOptions => getCORSHeadersByRequestAndOptions(request, corsOptions),
);
}

export function useCORS<TServerContext>(
Expand Down Expand Up @@ -143,13 +145,17 @@ export function useCORS<TServerContext>(
endResponse(response);
}
},
async onResponse({ request, serverContext, response }) {
const headers = await getCORSResponseHeaders<any>(request, corsOptionsFactory, serverContext);
if (headers != null) {
for (const headerName in headers) {
response.headers.set(headerName, headers[headerName]);
}
}
onResponse({ request, serverContext, response }) {
return handleMaybePromise(
() => getCORSResponseHeaders(request, corsOptionsFactory, serverContext),
headers => {
if (headers != null) {
for (const headerName in headers) {
response.headers.set(headerName, headers[headerName]);
}
}
},
);
},
};
}
8 changes: 3 additions & 5 deletions packages/server/src/plugins/useErrorHandling.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Response as DefaultResponseCtor } from '@whatwg-node/fetch';
import { handleMaybePromise } from '@whatwg-node/promise-helpers';
import { handleMaybePromise, MaybePromise } from '@whatwg-node/promise-helpers';
import type { ServerAdapterPlugin } from './types.js';

export function createDefaultErrorHandler<TServerContext = {}>(
Expand Down Expand Up @@ -44,17 +44,15 @@ export type ErrorHandler<TServerContext> = (
e: any,
request: Request,
ctx: TServerContext,
) => Response | Promise<Response> | void;
) => MaybePromise<Response> | void;

export function useErrorHandling<TServerContext>(
onError?: ErrorHandler<TServerContext>,
): ServerAdapterPlugin<TServerContext> {
return {
onRequest({ requestHandler, setRequestHandler, fetchAPI }) {
const errorHandler = onError || createDefaultErrorHandler<TServerContext>(fetchAPI.Response);
setRequestHandler(function handlerWithErrorHandling(request, serverContext):
| Promise<Response>
| Response {
setRequestHandler(function handlerWithErrorHandling(request, serverContext) {
return handleMaybePromise(
() => requestHandler(request, serverContext),
response => response,
Expand Down
43 changes: 20 additions & 23 deletions packages/server/src/types.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import type { RequestListener } from 'node:http';
import { MaybePromise, MaybePromiseLike } from '@whatwg-node/promise-helpers';
import type { NodeRequest, NodeResponse } from './utils.js';
import { UWSHandler, UWSRequest, UWSResponse } from './uwebsockets.js';

export interface FetchEvent extends Event {
waitUntil(f: Promise<void> | void): void;
waitUntil(f: MaybePromise<void>): void;
request: Request;
respondWith(r: Response | PromiseLike<Response>): void;
respondWith(r: MaybePromiseLike<Response>): void;
}

export interface ServerAdapterBaseObject<
Expand All @@ -27,28 +28,24 @@ export interface ServerAdapterObject<TServerContext> extends EventListenerObject
handleRequest: (
request: Request,
ctx: TServerContext & Partial<ServerAdapterInitialContext>,
) => Promise<Response> | Response;
) => MaybePromise<Response>;
/**
* WHATWG Fetch spec compliant `fetch` function that can be used for testing purposes.
*/
fetch(request: Request, ctx: TServerContext): Promise<Response> | Response;
fetch(request: Request, ...ctx: Partial<TServerContext>[]): Promise<Response> | Response;
fetch(urlStr: string, ctx: TServerContext): Promise<Response> | Response;
fetch(urlStr: string, ...ctx: Partial<TServerContext>[]): Promise<Response> | Response;
fetch(urlStr: string, init: RequestInit, ctx: TServerContext): Promise<Response> | Response;
fetch(request: Request, ctx: TServerContext): MaybePromise<Response>;
fetch(request: Request, ...ctx: Partial<TServerContext>[]): MaybePromise<Response>;
fetch(urlStr: string, ctx: TServerContext): MaybePromise<Response>;
fetch(urlStr: string, ...ctx: Partial<TServerContext>[]): MaybePromise<Response>;
fetch(urlStr: string, init: RequestInit, ctx: TServerContext): MaybePromise<Response>;
fetch(
urlStr: string,
init: RequestInit,
...ctx: Partial<TServerContext>[]
): Promise<Response> | Response;
fetch(url: URL, ctx: TServerContext): Promise<Response> | Response;
fetch(url: URL, ...ctx: Partial<TServerContext>[]): Promise<Response> | Response;
fetch(url: URL, init: RequestInit, ctx: TServerContext): Promise<Response> | Response;
fetch(
url: URL,
init: RequestInit,
...ctx: Partial<TServerContext>[]
): Promise<Response> | Response;
): MaybePromise<Response>;
fetch(url: URL, ctx: TServerContext): MaybePromise<Response>;
fetch(url: URL, ...ctx: Partial<TServerContext>[]): MaybePromise<Response>;
fetch(url: URL, init: RequestInit, ctx: TServerContext): MaybePromise<Response>;
fetch(url: URL, init: RequestInit, ...ctx: Partial<TServerContext>[]): MaybePromise<Response>;
/**
* This function takes Node's request object and returns a WHATWG Fetch spec compliant `Response` object.
*
Expand All @@ -57,15 +54,15 @@ export interface ServerAdapterObject<TServerContext> extends EventListenerObject
handleNodeRequest(
nodeRequest: NodeRequest,
...ctx: Partial<TServerContext & ServerAdapterInitialContext>[]
): Promise<Response> | Response;
): MaybePromise<Response>;
/**
* This function takes Node's request and response objects and returns a WHATWG Fetch spec compliant `Response` object.
*/
handleNodeRequestAndResponse(
nodeRequest: NodeRequest,
nodeResponseOrContainer: { raw: NodeResponse } | NodeResponse,
...ctx: Partial<TServerContext & ServerAdapterInitialContext>[]
): Promise<Response> | Response;
): MaybePromise<Response>;
/**
* A request listener function that can be used with any Node server variation.
*/
Expand All @@ -81,11 +78,11 @@ export interface ServerAdapterObject<TServerContext> extends EventListenerObject
handle(
requestLike: RequestLike,
...ctx: Partial<TServerContext & ServerAdapterInitialContext>[]
): Promise<Response> | Response;
): MaybePromise<Response>;
handle(
request: Request,
...ctx: Partial<TServerContext & ServerAdapterInitialContext>[]
): Promise<Response> | Response;
): MaybePromise<Response>;
handle(
fetchEvent: FetchEvent & Partial<TServerContext & ServerAdapterInitialContext>,
...ctx: Partial<TServerContext>[]
Expand All @@ -98,7 +95,7 @@ export interface ServerAdapterObject<TServerContext> extends EventListenerObject
handle(
container: { request: Request } & Partial<TServerContext & ServerAdapterInitialContext>,
...ctx: Partial<TServerContext & ServerAdapterInitialContext>[]
): Promise<Response> | Response;
): MaybePromise<Response>;

disposableStack: AsyncDisposableStack;

Expand Down Expand Up @@ -128,7 +125,7 @@ export type ServerAdapter<
export type ServerAdapterRequestHandler<TServerContext> = (
request: Request,
ctx: TServerContext & ServerAdapterInitialContext,
) => Promise<Response> | Response;
) => MaybePromise<Response>;

export type ServerAdapterNodeContext = {
req: NodeRequest;
Expand Down
2 changes: 1 addition & 1 deletion packages/server/src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -477,7 +477,7 @@ export function isolateObject<TIsolatedObject extends object>(
}

export function handleAbortSignalAndPromiseResponse(
response$: Promise<Response> | Response,
response$: MaybePromise<Response>,

Check failure on line 480 in packages/server/src/utils.ts

View workflow job for this annotation

GitHub Actions / server (native)

Cannot find name 'MaybePromise'.

Check failure on line 480 in packages/server/src/utils.ts

View workflow job for this annotation

GitHub Actions / e2e / aws-lambda

Cannot find name 'MaybePromise'.

Check failure on line 480 in packages/server/src/utils.ts

View workflow job for this annotation

GitHub Actions / server (ponyfill)

Cannot find name 'MaybePromise'.

Check failure on line 480 in packages/server/src/utils.ts

View workflow job for this annotation

GitHub Actions / esm

Cannot find name 'MaybePromise'.

Check failure on line 480 in packages/server/src/utils.ts

View workflow job for this annotation

GitHub Actions / e2e / azure-function

Cannot find name 'MaybePromise'.

Check failure on line 480 in packages/server/src/utils.ts

View workflow job for this annotation

GitHub Actions / server (undici)

Cannot find name 'MaybePromise'.

Check failure on line 480 in packages/server/src/utils.ts

View workflow job for this annotation

GitHub Actions / e2e / cloudflare-workers

Cannot find name 'MaybePromise'.

Check failure on line 480 in packages/server/src/utils.ts

View workflow job for this annotation

GitHub Actions / type check

Cannot find name 'MaybePromise'.

Check failure on line 480 in packages/server/src/utils.ts

View workflow job for this annotation

GitHub Actions / e2e / cloudflare-modules

Cannot find name 'MaybePromise'.

Check failure on line 480 in packages/server/src/utils.ts

View workflow job for this annotation

GitHub Actions / alpha / snapshot

Cannot find name 'MaybePromise'.
abortSignal: AbortSignal,
) {
if (abortSignal?.aborted) {
Expand Down

0 comments on commit d59e1ff

Please sign in to comment.