Repository: feathersjs/feathers (TypeScript)

Issue:
After all and after method specific hook order changed in V5
### Steps to reproduce

If a service has the following hooks:

```js
after: {
  all: [context => console.log('After all')],
  find: [context => console.log('After find')],
}
```

In V4 it outputs:

```
After all
After find
```

In V5 it outputs:

```
After find
After all
```

My best current understanding is that it's because of how the before/after/error hooks get collected in a single "collected" chain using the new around hook mechanic here: https://github.com/feathersjs/feathers/blob/5854dea7f610262121a49623ec5bbd474dcd3ef3/packages/feathers/src/hooks.ts#L60-L65

What happens is that the when we spread all and then method specific hooks:

```js
...(collected.all || []),
...(collected[method] || [])
```

The order for the after hooks becomes:

afterAll() {
  await next()
  context => console.log('After all')
}

afterFind() {
  await next()
  context => console.log('After find')
}

and when that unwinds we first yield after find and then after all in that (backwards incompatible) order.


### Expected behavior

V5 keeps backwards compatibility in the hooks and logs:

```
After all
After find
```

### System configuration

**Module versions**:
@feathersjs/feathers@5.0.0-pre.35



Discussion:
Failing test case for `feathers/test/hooks/after.test.ts`:

```ts
it.only('.after all and method specific hooks run in the correct order (#3002)', async () => {
    const app = feathers().use('/dummy', {
      async get(id: any) {
        return { id, items: [] as any }
      }
    })
    const service = app.service('dummy')

    service.hooks({
      after: {
        all(context) {
          context.result.items.push('first')

          return context
        },
        get: [
          function (context) {
            context.result.items.push('second')

            return context
          },
          function (context) {
            context.result.items.push('third')

            return context
          }
        ]
      }
    })

    const data = await service.get(10)

    assert.deepStrictEqual(data.items, ['first', 'second', 'third'])
  })
```



Patch:
diff --git a/packages/feathers/src/hooks.ts b/packages/feathers/src/hooks.ts
index 6d3dd4b0ec..acb857301d 100644
--- a/packages/feathers/src/hooks.ts
+++ b/packages/feathers/src/hooks.ts
@@ -26,7 +26,8 @@ type HookStore = {
   before: { [method: string]: HookFunction[] }
   after: { [method: string]: HookFunction[] }
   error: { [method: string]: HookFunction[] }
-  collected: { [method: string]: AroundHookFunction[] }
+  collected: { [method: string]: AroundHookFunction[] },
+  collectedAll: { before?: AroundHookFunction[], after?: AroundHookFunction[] }
 }
 
 type HookEnabled = { __hooks: HookStore }
@@ -55,13 +56,14 @@ export function convertHookData(input: any) {
 }
 
 export function collectHooks(target: HookEnabled, method: string) {
-  const { collected, around } = target.__hooks
+  const { collected, collectedAll, around } = target.__hooks
 
   return [
     ...(around.all || []),
     ...(around[method] || []),
-    ...(collected.all || []),
-    ...(collected[method] || [])
+    ...(collectedAll.before || []),
+    ...(collected[method] || []),
+    ...(collectedAll.after || []),
   ] as AroundHookFunction[]
 }
 
@@ -72,7 +74,8 @@ export function enableHooks(object: any) {
     before: {},
     after: {},
     error: {},
-    collected: {}
+    collected: {},
+    collectedAll: {},
   }
 
   Object.defineProperty(object, '__hooks', {
@@ -101,14 +104,31 @@ export function enableHooks(object: any) {
 
         storeHooks.push(...mapHooks)
 
-        if (store.before[method] || store.after[method] || store.error[method]) {
-          const collected = collect({
-            before: store.before[method] || [],
-            after: store.after[method] || [],
-            error: store.error[method] || []
-          })
-
-          store.collected[method] = [collected]
+        if (method === 'all') {
+          if (store.before[method] || store.error[method]) {
+            const beforeAll = collect({
+              before: store.before[method] || [],
+              error: store.error[method] || []
+            })
+            store.collectedAll.before = [beforeAll]
+          }
+
+          if (store.after[method]) {
+            const afterAll = collect({
+              after: store.after[method] || [],
+            })
+            store.collectedAll.after = [afterAll]
+          }
+        } else {
+          if (store.before[method] || store.after[method] || store.error[method]) {
+            const collected = collect({
+              before: store.before[method] || [],
+              after: store.after[method] || [],
+              error: store.error[method] || []
+            })
+
+            store.collected[method] = [collected]
+          }
         }
       })
     )


Test patch:
diff --git a/packages/feathers/test/hooks/after.test.ts b/packages/feathers/test/hooks/after.test.ts
index 29a1810420..d4440472fe 100644
--- a/packages/feathers/test/hooks/after.test.ts
+++ b/packages/feathers/test/hooks/after.test.ts
@@ -381,4 +381,39 @@ describe('`after` hooks', () => {
       test: 43
     })
   })
+
+  it('.after all and method specific hooks run in the correct order (#3002)', async () => {
+    const app = feathers().use('/dummy', {
+      async get(id: any) {
+        return { id, items: [] as any }
+      }
+    })
+    const service = app.service('dummy')
+
+    service.hooks({
+      after: {
+        all(context) {
+          context.result.items.push('first')
+
+          return context
+        },
+        get: [
+          function (context) {
+            context.result.items.push('second')
+
+            return context
+          },
+          function (context) {
+            context.result.items.push('third')
+
+            return context
+          }
+        ]
+      }
+    })
+
+    const data = await service.get(10)
+
+    assert.deepStrictEqual(data.items, ['first', 'second', 'third'])
+  })
 })