@data-eden/network
Advanced tools
Comparing version 0.3.2 to 0.4.0
@@ -12,3 +12,8 @@ import { | ||
import { buildFetch, Middleware, NormalizedFetch } from '@data-eden/network'; | ||
import { | ||
buildFetch, | ||
Middleware, | ||
MiddlewareMetadata, | ||
NormalizedFetch, | ||
} from '@data-eden/network'; | ||
import { createServer } from '@data-eden/shared-test-utilities'; | ||
@@ -216,2 +221,32 @@ | ||
test('middlewares can access the `buildFetch` result', async () => { | ||
const steps: string[] = []; | ||
const fetches: (typeof fetch)[] = []; | ||
const middleware: Middleware = async ( | ||
request: Request, | ||
next: NormalizedFetch, | ||
metadata: MiddlewareMetadata | ||
) => { | ||
const fetchIndex = fetches.findIndex((item) => item === metadata.fetch); | ||
steps.push(`invoked from ${fetchIndex}`); | ||
return next(request); | ||
}; | ||
fetches.push(buildFetch([middleware])); | ||
fetches.push(buildFetch([middleware])); | ||
await fetches[1]('http://www.example.com/resource'); | ||
await fetches[0]('http://www.example.com/resource'); | ||
await fetches[1]('http://www.example.com/resource'); | ||
expect(steps).toMatchInlineSnapshot(` | ||
[ | ||
"invoked from 1", | ||
"invoked from 0", | ||
"invoked from 1", | ||
] | ||
`); | ||
}); | ||
test('should be able to override fetch', async () => { | ||
@@ -218,0 +253,0 @@ expect.assertions(1); |
export type Fetch = typeof fetch; | ||
export type NormalizedFetch = (request: Request) => Promise<Response>; | ||
export interface MiddlewareMetadata { | ||
/** | ||
The specific function that was returned by `buildFetch`. This can be useful | ||
to allow middlewares to handle state that is specifically related to one | ||
`buildFetch` result over another one. | ||
Note: The middleware **must not** actually invoke this `fetch` method (doing so | ||
will throw due to infinite recursion). | ||
*/ | ||
fetch: Fetch; | ||
} | ||
export type Middleware = ( | ||
@@ -11,3 +22,7 @@ /** | ||
*/ | ||
next: NormalizedFetch) => Promise<Response>; | ||
next: NormalizedFetch, | ||
/** | ||
* metadata regarding the current request | ||
*/ | ||
metadata: MiddlewareMetadata) => Promise<Response>; | ||
export interface BuildFetchOptions { | ||
@@ -32,2 +47,4 @@ /** | ||
/** | ||
* Builds a `fetch`-compatible function that runs `middleware`s on each | ||
* request. | ||
* | ||
@@ -34,0 +51,0 @@ * @param middlewares {Middleware[]} array of middlewares |
@@ -1,6 +0,1 @@ | ||
function combine(next, middleware) { | ||
return async (request) => { | ||
return middleware(request, next); | ||
}; | ||
} | ||
function globalFetch(request) { | ||
@@ -10,2 +5,4 @@ return fetch(request); | ||
/** | ||
* Builds a `fetch`-compatible function that runs `middleware`s on each | ||
* request. | ||
* | ||
@@ -21,10 +18,19 @@ * @param middlewares {Middleware[]} array of middlewares | ||
const _fetch = options?.fetch || globalFetch; | ||
let result; | ||
const curriedMiddlewares = [...middlewares] | ||
.reverse() | ||
.reduce(combine, _fetch); | ||
return async (rawRequest, init) => { | ||
.reduce((next, middleware) => { | ||
return async (request) => { | ||
const metadata = { | ||
fetch: result, | ||
}; | ||
return middleware(request, next, metadata); | ||
}; | ||
}, _fetch); | ||
result = async (rawRequest, init) => { | ||
const normalizedRequest = new Request(rawRequest, init); | ||
return curriedMiddlewares(normalizedRequest); | ||
}; | ||
return result; | ||
} | ||
//# sourceMappingURL=fetch.js.map |
export { buildFetch } from './fetch.js'; | ||
export type { Middleware, NormalizedFetch } from './fetch.js'; | ||
export { hasPendingRequests, getPendingRequestState, default as SettledTrackingMiddleware, requestsCompleted, } from './settled-tracking-middleware.js'; | ||
export type { FetchDebugInfo, RequestsCompletedOptions, } from './settled-tracking-middleware.js'; | ||
export type { Middleware, MiddlewareMetadata, NormalizedFetch, } from './fetch.js'; | ||
//# sourceMappingURL=index.d.ts.map |
export { buildFetch } from './fetch.js'; | ||
export { hasPendingRequests, getPendingRequestState, default as SettledTrackingMiddleware, requestsCompleted, } from './settled-tracking-middleware.js'; | ||
//# sourceMappingURL=index.js.map |
{ | ||
"name": "@data-eden/network", | ||
"version": "0.3.2", | ||
"version": "0.4.0", | ||
"repository": { | ||
@@ -11,2 +11,5 @@ "type": "git", | ||
"type": "module", | ||
"imports": { | ||
"#settled-tracking-middleware": "./src/settled-tracking-middleware.ts" | ||
}, | ||
"exports": { | ||
@@ -19,3 +22,5 @@ ".": { | ||
"default": "./dist/index.js" | ||
} | ||
}, | ||
"./NOTE01": "This should be removed once https://github.com/vitejs/vite/pull/7770 lands, and we can use `imports` properly", | ||
"./-private/settled-tracking-middleware": "./dist/settled-tracking-middleware.js" | ||
}, | ||
@@ -29,3 +34,3 @@ "main": "./dist/index.js", | ||
"devDependencies": { | ||
"@data-eden/shared-test-utilities": "0.3.2", | ||
"@data-eden/shared-test-utilities": "0.4.0", | ||
"cross-fetch": "^3.1.5" | ||
@@ -32,0 +37,0 @@ }, |
@@ -5,2 +5,14 @@ export type Fetch = typeof fetch; | ||
export interface MiddlewareMetadata { | ||
/** | ||
The specific function that was returned by `buildFetch`. This can be useful | ||
to allow middlewares to handle state that is specifically related to one | ||
`buildFetch` result over another one. | ||
Note: The middleware **must not** actually invoke this `fetch` method (doing so | ||
will throw due to infinite recursion). | ||
*/ | ||
fetch: Fetch; | ||
} | ||
export type Middleware = ( | ||
@@ -14,3 +26,8 @@ /** | ||
*/ | ||
next: NormalizedFetch | ||
next: NormalizedFetch, | ||
/** | ||
* metadata regarding the current request | ||
*/ | ||
metadata: MiddlewareMetadata | ||
) => Promise<Response>; | ||
@@ -37,11 +54,2 @@ | ||
function combine( | ||
next: NormalizedFetch, | ||
middleware: Middleware | ||
): NormalizedFetch { | ||
return async (request: Request) => { | ||
return middleware(request, next); | ||
}; | ||
} | ||
function globalFetch(request: Request): Promise<Response> { | ||
@@ -52,2 +60,4 @@ return fetch(request); | ||
/** | ||
* Builds a `fetch`-compatible function that runs `middleware`s on each | ||
* request. | ||
* | ||
@@ -69,10 +79,25 @@ * @param middlewares {Middleware[]} array of middlewares | ||
let result: Fetch; | ||
const curriedMiddlewares: NormalizedFetch = [...middlewares] | ||
.reverse() | ||
.reduce(combine, _fetch); | ||
.reduce( | ||
(next: NormalizedFetch, middleware: Middleware): NormalizedFetch => { | ||
return async (request: Request) => { | ||
const metadata = { | ||
fetch: result, | ||
}; | ||
return async (rawRequest: RequestInfo | URL, init?: RequestInit) => { | ||
return middleware(request, next, metadata); | ||
}; | ||
}, | ||
_fetch | ||
); | ||
result = async (rawRequest: RequestInfo | URL, init?: RequestInit) => { | ||
const normalizedRequest = new Request(rawRequest, init); | ||
return curriedMiddlewares(normalizedRequest); | ||
}; | ||
return result; | ||
} |
export { buildFetch } from './fetch.js'; | ||
export { | ||
hasPendingRequests, | ||
getPendingRequestState, | ||
default as SettledTrackingMiddleware, | ||
requestsCompleted, | ||
} from './settled-tracking-middleware.js'; | ||
export type { Middleware, NormalizedFetch } from './fetch.js'; | ||
export type { | ||
FetchDebugInfo, | ||
RequestsCompletedOptions, | ||
} from './settled-tracking-middleware.js'; | ||
export type { | ||
Middleware, | ||
MiddlewareMetadata, | ||
NormalizedFetch, | ||
} from './fetch.js'; |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
150031
24
1438