diff --git a/lib/api-internal.ts b/lib/api-internal.ts
index b49d5e808..7e79523f6 100644
--- a/lib/api-internal.ts
+++ b/lib/api-internal.ts
@@ -87,22 +87,27 @@ export function decorateApi(
) {
// read existing total and local
let current = scope.get(api.context) ?? { total: {}, local: {} };
+ let hasOwnContext = scope.hasOwn(api.context);
- let local = decorate(current.local, {
+ let total = hasOwnContext
+ ? current.total
+ : decorate(current.total, current.local);
+
+ let local = decorate(hasOwnContext ? current.local : {}, {
[options?.at ?? "max"]: decorator,
});
- if (!scope.hasOwn(api.context)) {
+ if (!hasOwnContext) {
scope.set(api.context, {
local,
- total: current.total,
+ total,
handle: api.core,
});
} else {
current.local = local;
}
- install(scope, api, current.total);
+ install(scope, api, total);
}
function decorate(base: Decorator, next: Decorator): Decorator {
diff --git a/test/api.test.ts b/test/api.test.ts
index 6e9083445..79a124277 100644
--- a/test/api.test.ts
+++ b/test/api.test.ts
@@ -289,6 +289,59 @@ describe("api", () => {
});
});
+ it("does not duplicate existing ancestor middleware when propagating later additions", async () => {
+ let api = createApi("test", {
+ *test(order: string[]): Operation {
+ return order;
+ },
+ });
+
+ await run(function* () {
+ yield* api.around({
+ *test(args, next) {
+ let [input] = args;
+ let output = yield* next(input.concat("parent-before"));
+ return output.concat("/parent-before");
+ },
+ });
+
+ let tester = yield* resource<{ test(): Operation }>(
+ function* (provide) {
+ let scope = yield* useScope();
+ yield* api.around({
+ *test(args, next) {
+ let [input] = args;
+ let output = yield* next(input.concat("child"));
+ return output.concat("/child");
+ },
+ });
+ yield* provide({
+ *test() {
+ return yield* scope.run(() => api.operations.test([]));
+ },
+ });
+ },
+ );
+
+ yield* api.around({
+ *test(args, next) {
+ let [input] = args;
+ let output = yield* next(input.concat("parent-after"));
+ return output.concat("/parent-after");
+ },
+ });
+
+ expect(yield* tester.test()).toEqual([
+ "parent-before",
+ "parent-after",
+ "child",
+ "/child",
+ "/parent-after",
+ "/parent-before",
+ ]);
+ });
+ });
+
it("isolates sibling scopes from each other's middleware", async () => {
let api = createApi("test", {
*test(order: string[]): Operation {