> ## Documentation Index
> Fetch the complete documentation index at: https://abxbus.archivebox.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Event Pattern Matching

> Use classes, strings, or wildcards for both handler registration and event lookup.

Event patterns are shared across both APIs:

* `bus.on(pattern, handler)` for subscriptions
* `bus.find(pattern, ...)` for history/future lookup

Both accept the same pattern forms:

* event class
* string event type name
* `'*'` wildcard (match everything)

Go and Rust use string event type names for low-level registration/lookup, plus typed payload/event APIs (`bus.On(...)` in Go, `EventSpec`/`BaseEvent` in Rust) when you want payload/result validation.

## Supported pattern forms

| Pattern                         | Matches                 | Best for                                                         |
| ------------------------------- | ----------------------- | ---------------------------------------------------------------- |
| Event class (`UserActionEvent`) | One concrete event type | Strong typing end-to-end                                         |
| String (`'UserActionEvent'`)    | Events by type name     | Dynamic routing/config-driven keys; primary Go/Rust pattern form |
| `'*'`                           | All event types         | Global observers, logging, bridges                               |

## `.on(...)` and `.find(...)` use the same pattern model

Use whichever operation you need, with the same pattern key:

* subscribe: `bus.on(UserActionEvent, handler)`
* find by class: `await bus.find(UserActionEvent)`
* find by string: `await bus.find('UserActionEvent')`
* wildcard subscribe/find: `bus.on('*', ...)`, `await bus.find('*', ...)`

## Examples

<Tabs>
  <Tab title="Python">
    ```python theme={null}
    from typing import Any
    from abxbus import BaseEvent, EventBus

    class UserActionEvent(BaseEvent[str]):
        action: str

    bus = EventBus('AppBus')

    async def on(event: UserActionEvent) -> str:
        # event is strongly typed here
        return f'action:{event.action}'

    def on_by_name(event: BaseEvent[Any]) -> None:
        # string patterns are looser; payload fields are not statically known
        print('by-name', event.event_type, getattr(event, 'action', None))
        # by-name UserActionEvent click

    def on_any(event: BaseEvent[Any]) -> None:
        print('wildcard', event.event_type)
        # wildcard UserActionEvent

    bus.on(UserActionEvent, on)
    bus.on('UserActionEvent', on_by_name)
    bus.on('*', on_any)

    event = await bus.emit(UserActionEvent(action='click')).now()
    result = await event.event_result()

    typed_match = await bus.find(UserActionEvent)          # UserActionEvent | None
    named_match = await bus.find('UserActionEvent')        # BaseEvent[Any] | None
    wildcard_match = await bus.find('*', future=5)         # BaseEvent[Any] | None
    ```
  </Tab>

  <Tab title="TypeScript">
    ```ts theme={null}
    import { BaseEvent, EventBus } from 'abxbus'
    import { z } from 'zod'

    const UserActionEvent = BaseEvent.extend('UserActionEvent', {
      action: z.string(),
      event_result_type: z.string(),
    })

    const bus = new EventBus('AppBus')

    bus.on(UserActionEvent, (event) => {
      // event is strongly typed here
      return `action:${event.action}`
    })

    bus.on('UserActionEvent', (event) => {
      // string patterns are looser; event is BaseEvent-like at compile time
      console.log('by-name', event.event_type)
      return undefined
    })

    bus.on('*', (event) => {
      console.log('wildcard', event.event_type)
      return undefined
    })

    const typedMatch = await bus.find(UserActionEvent)      // InstanceType<typeof UserActionEvent> | null
    const namedMatch = await bus.find('UserActionEvent')    // BaseEvent | null
    const wildcardMatch = await bus.find('*', { future: 5 }) // BaseEvent | null
    ```
  </Tab>

  <Tab title="Rust">
    ```rust theme={null}
    use abxbus::{
        event,
        event_bus::EventBus,
        BaseEvent,
    };
    use futures::executor::block_on;

    event! {
        struct UserActionEvent {
            action: String,
            event_result_type: String,
        }
    }

    let bus = EventBus::new(Some("AppBus".to_string()));

    bus.on(UserActionEvent, |event: UserActionEvent| async move {
        Ok(format!("action:{}", event.action))
    });

    let event = bus.emit(UserActionEvent {
        action: "click".to_string(),
        ..Default::default()
    });
    block_on(event.now());

    let typed_match = block_on(bus.find::<UserActionEvent>(true, None));
    let named_match = block_on(bus.find("UserActionEvent", true, None, None));
    let wildcard_match = block_on(bus.find("*", false, Some(5.0), None));
    ```
  </Tab>

  <Tab title="Go">
    ```go theme={null}
    package main

    import (
    	"fmt"

    	abxbus "github.com/ArchiveBox/abxbus/abxbus-go"
    )

    type UserActionEvent struct {
    	Action string `json:"action"`
    }

    func main() {
    	bus := abxbus.NewEventBus("AppBus", nil)

    	bus.On(func(event UserActionEvent) (string, error) {
    		return fmt.Sprintf("action:%s", event.Action), nil
    	})

    	bus.On("UserActionEvent", "on_by_name", func(event *abxbus.BaseEvent) (any, error) {
    		fmt.Println("by-name", event.EventType, event.Payload["action"])
    		// by-name UserActionEvent click
    		return nil, nil
    	}, nil)

    	bus.OnEventName("*", "on_any", func(event *abxbus.BaseEvent) (any, error) {
    		fmt.Println("wildcard", event.EventType)
    		// wildcard UserActionEvent
    		return nil, nil
    	}, nil)

    	_, err := bus.Emit(UserActionEvent{Action: "click"}).EventResult()
    	if err != nil {
    		panic(err)
    	}

    	namedMatch, err := bus.FindEventName("UserActionEvent", nil, nil)
    	if err != nil {
    		panic(err)
    	}
    	wildcardMatch, err := bus.FindEventName("*", nil, &abxbus.FindOptions{Future: 5.0})
    	if err != nil {
    		panic(err)
    	}
    	_, _ = namedMatch, wildcardMatch
    }
    ```
  </Tab>
</Tabs>

## Why event classes are preferred for typing

Event classes preserve the most useful static typing:

* handler input shape is specific (payload fields are known)
* event result typing stays aligned with `event_result_type` / generic result type
* `.find(EventClass)` returns the specific event type

String keys and `'*'` are intentionally looser:

* Python: treat as `BaseEvent[Any]`
* TypeScript: typed as base `BaseEvent`/unknown-oriented handler return checks
* Rust: typed handlers use `bus.on(MyEvent, ...)`; raw string/wildcard registration is reserved for low-level forwarding internals.
* Go: typed handlers use `bus.On(...)`; string/wildcard handlers use `bus.OnEventName(...)` and receive `*BaseEvent`

Use string/wildcard patterns when you need dynamic behavior. Use classes whenever you want strict payload/result type hints through handlers and lookups.
