around() in www/context/context-api.ts accepts a Partial<Around<A>>, but it
rebuilds every field of the api rather than only the ones the caller
supplied. For an omitted field, around[field] is undefined, and the
replacement middleware closes over it anyway:
yield* context.set(fields.reduce((sum, field) => {
let prior = current[field] as Middleware<any[], any>;
let middleware = around[field] as Middleware<any[], any>; // undefined
return Object.assign(sum, {
[field]: (args: any, next: any) =>
middleware(args, (...args) => prior(args, next)), // throws
});
}, Object.assign({}, current)));
The override itself appears to work. The failure comes later, when something
calls one of the fields that was not overridden:
TypeError: middleware is not a function
at context-api.ts:67:11
Reproduction
interface Demo {
a(): Operation<string>;
b(): Operation<string>;
}
const demo = createApi<Demo>("demo", {
*a() { return "a"; },
*b() { return "b"; },
});
await main(function* () {
yield* demo.around({
*a(args, next) { return yield* next(...args); }, // `b` omitted
});
yield* demo.operations.a(); // fine
yield* demo.operations.b(); // TypeError: middleware is not a function
});
Why it has not been hit
Every around() call in the repository happens to supply all of its api's
fields:
FetchApi and ProcessApi have a single field each, so a partial is not
expressible.
- All four
loggerApi.around call sites (context/logging.ts,
testing/logging.ts) list info, debug, warn and error.
It surfaces as soon as there is a multi-field api where overriding one field is
the natural thing to write. UrlApi in #1250 is the first.
Fix
A field the partial omits should keep the middleware it already has. Since the
reduce seeds with Object.assign({}, current), that is just an early return:
let middleware = around[field] as Middleware<any[], any> | undefined;
if (!middleware) {
return sum;
}
Filed for the record — the fix is already in #1250 as fc19224a, since that PR
needs it. Happy to split it out into its own PR against v4 if you would rather
it land independently of the url work.
around()inwww/context/context-api.tsaccepts aPartial<Around<A>>, but itrebuilds every field of the api rather than only the ones the caller
supplied. For an omitted field,
around[field]isundefined, and thereplacement middleware closes over it anyway:
The override itself appears to work. The failure comes later, when something
calls one of the fields that was not overridden:
Reproduction
Why it has not been hit
Every
around()call in the repository happens to supply all of its api'sfields:
FetchApiandProcessApihave a single field each, so a partial is notexpressible.
loggerApi.aroundcall sites (context/logging.ts,testing/logging.ts) listinfo,debug,warnanderror.It surfaces as soon as there is a multi-field api where overriding one field is
the natural thing to write.
UrlApiin #1250 is the first.Fix
A field the partial omits should keep the middleware it already has. Since the
reduce seeds with
Object.assign({}, current), that is just an early return:Filed for the record — the fix is already in #1250 as
fc19224a, since that PRneeds it. Happy to split it out into its own PR against
v4if you would ratherit land independently of the url work.